Wednesday, September 13, 2017

The Open2 Engine - part 5 - Whirlwind JavaScript

    Okay, with HMTL we made a document, CSS made that document pretty, now with JavaScript we can make that document act and react.  So let's do another Flash-fast tour, hold on to your hats...

Variables
    Okay, let's start with variables - how we store data.  If our program is going to do something, odds are it's going to need to remember information.  A variable is just that, a place to put some data.  Creating a variable is usually with "var" like this...

var variableName = "data";

    Now, the "variableName" is an example of "Camel Case" which is the JavaScript convention of naming everything with a lower-case word, and adding capitalized words after to create a descriptive name.  You could name a variable anything beginning with '$', '_', or a letter - after which you can use the same and numbers (so can't start with a number, can use it later though).
    Variables come in different types, and the one I made above is a "string" - a series of numbers/letters/symbols, like a sentence.  Since a string is created by using quotes, if you want quotes in the string itself you've got to mix them...

var htmlElement = 'myElement attribute="value" something';

or you have to "escape" them with the backslash...

var htmlElement = "myElement attribute=\"value\" something";

Notice that I've put a semicolon at the end of each line, the semicolon is used to tell JavaScript where the end of a command is at (like how a period shows the end of a sentence).

    Instead of making a string, I could make a number, like so...

var myNumber = 10;

However, JavaScript is a "loosely typed" language, which means a variable can be just about anything.  That will occasionally make life interesting when a variable is not what you think it is.       
    Here's an example, let's add two numbers together...

var A = 1;
var B = 1;
var C = A + B;
console.log(C);
>2

Okay, the "console" is a hidden developer tool (you can access it from a browser or your programming IDE, you can't see it with just a text editor).  I'll use the ">" at the start if a line to show what the console would output (if you were running this and not reading it :).  So in our example above we get just what we expect, we set two variables, each is equal to the number 1, and we add them together to get the number 2.
    But what if we accidentally put some quotes around one of our variables?  Like this...

var A = "1";
var B = 1;
var C = A + B;
console.log(C);
>11

Huh?  Well, by putting the quotes around the first variable we turned it into a string instead of a number, and addition on a string becomes "concatenation" (or, combining the contents of two strings into one)...

var A = "this";
var B = "WORD";
var C = A + B;
console.log(C);
>thisWORD

    Because JavaScript doesn't track variables too closely, I like to do it myself (this number/string thing has bit me on the rump before) so I can remember what something is.  Camel Case is not very descriptive to me, I prefer something called "Hungarian Notation" where you prefix every variable name with the type of data that variable is supposed to hold.
    So, the way I would write a string is to start with the letter "s" (for string)...

var sFirstName = "Bob";
var sAddress = "123 Lane";

    Most numbers I've had to track were whole numbers, or integers, so they start with "i"...

var iLocationsDiscovered = 0;
var iHitPoints = 20;

    There's not really a right or wrong way, it depends on your audience.  If you're programming as a part of a team, you should use whatever naming convention the team uses (duh).  Since I'm writing this by myself (and I'm old and crotchety) I'm going to use my own style of naming (which you should know since you're going to have to read it :).

    In my projects so far, pretty much the first thing I've done is start declaring the variables I'm going to need.  But, while strings and numbers are nice, they are pretty much just one piece of information per variable, what if we wanted to store several bits of data in one place?


Arrays
    Think of a backpack.  It's a single object, but it can contain multiple items within itself.  That's basically an Array.  We define an array with brackets, and separate the items within by commas...

var aBackpack = [rock, knife, apple];

So how do we find something in the array?  By using it's "index", which is a number - starting with zero! - that points to the array's contents...

console.log(aBackpack[0]);
>rock

console.log(aBackpack[1]);
>knife

console.log(aBackpack[2]);
>apple


We can also make an empty array and then define the contents like variables...

var aBackpack = [];
var aBackpack[0] = "rock";
var aBackpack[1] = "knife";
var aBackpack[2] = "apple";

Arrays also have "methods", special commands we can call to interact with the array.  One is "push" which adds an item to the end of the array.  "Pop" will delete the last item, and "length" will say how many items are in the array...

var aBackpack = [rock, knife, apple];
console.log(aBackpack.length);
>3

aBackpack.push(potion);
console.log(aBackpack);
console.log(aBackpack.length);
>rock, knife, apple, potion
>4
 
aBackpack.pop;
console.log(aBackpack);
>rock, knife, apple


    Arrays can hold any kind of data, strings, numbers, even other arrays!  Arrays can also hold objects...


Objects
    Like an array, an Object is a way to group several variables together.  Objects are made with curly braces "{ }" and hold key: value pairs...

oPlayer= {
    Name: "Bob",
    Class: "Fighter",
    Strength: 10,
    hitPoints: 20,
    Backpack: [rock, knife, apple]
};

These are all "properties" and can be accessed with "dot notation" or the objectName.propertyName...

console.log(oPlayer.Name);
>Bob

console.log(oPlayer.Backpack[1]);
>knife

    We can also give objects "methods" or commands that they can carry out, and we can add a property or method by defining the object with it...

oPlayer.Punch = function () {
    console.log("pow!")
};

oPlayer.Punch();
>pow!

    Objects are a great way to keep information together, but let's look at how to actually act on that information with functions...


Functions
    Data just sits there, to act on it we need functions.  Declaring a new function looks like...

function functionName (parameters) { commands };

Let's make a hypothetical "Attack Turn" function, we'll have a monster attack a character (which will be a nice complex example).  Virtually every function is going to act on some variables, so let's think about the ones we need.  We're going to need a monster and a player, so we'll make them 2 objects.  Each is going to need a chance to hit, which we'll turn around and say is a % chance "to be hit" (you'll see).  Each is also going to need the damage they do, and the health they have.  That should do for a bare-minimum example.  So here are my two objects...

oPlayer = {
    ToBeHit: 40;
    Health: 20;
    Damage: 5;
};

oMonster = {
    ToBeHit: 60;
    Health: 10;
    Damage: 10;
};

I'm giving my player lower odds of being hit, but the monster does more damage (just because, it's an example :).
    Now, the first things we need to create our function is a name and the parameters.  "Parameters" are just variables we're going to pass to the function for it to work on.  In this case, I'm going to pass two parameters, the attacker and the defender.  So I've got this...

function fAttackTurn (attacker, defender) { };

Okay, now we need the code, the commands of what the function should do.  There are some functions that JavaScript has created for us, one of them is "Math.random" which we can use to get a random number.  So we're going to get the chance to hit needed, then a random number between 1 and 100, compare the two, and if the random number is lower than or equal to the chance to hit, we'll do the attacker's damage to the defender's health.  This should show us a lot of what functions can do.
    First, inside the function let's make a variable for the attack roll (our random number)...

function fAttackTurn (attacker, defender) {
    var iAttackRoll;
};

Well, that makes an "undefined" variable, one that has no value (not even zero).  Let's make it equal to the JavaScript function for our 1-100 number (which is, well, complicated)...

function fAttackTurn (attacker, defender) {
    var iAttackRoll = Math.floor(Math.random () * 100) + 1;
};

Yeah, it's a bit complicated, functions can get that way.  Anyways, that will give us a random number between 1 and 100.  So let's compare that number to the defender's odds of being hit and see if it's less than or equal to (a hit) or greater than (a miss)...

function fAttackTurn (attacker, defender) {
    var iAttackRoll = Math.floor(Math.random () * 100) + 1;
    if ( iAttackRoll <= defender.ToBeHit){

    } else {

    }
};

Well, what do we want to do?  Either way let's do the console.log of what we got, and if we do hit then we want to subtract the attacker's damage from the defender's health...

function fAttackTurn (attacker, defender) {
    var iAttackRoll = Math.floor(Math.random () * 100) + 1;
    if ( iAttackRoll <= defender.ToBeHit){
       console.log("You hit!")
       defender.Health = defender.Health - attacker.Damage
    } else {
       console.log("You missed!")
    }
};

Okay, let's stop and look at how we'd "call" this function, or run it.  We'll have the monster attack the character...

fAttackTurn (oMonster, oPlayer)

To have the player attack the monster, we reverse the parameters...

fAttackTurn (oPlayer, oMonster)

    Okay, so let's stop and look at some of that function in more detail.


Decisions and Loops
    One of the things our "Attack Turn" function had to do was make a decision - it had to decide if the attack roll was higher than the defender's defense.  To do that we used an "if" statement

if ( iAttackRoll <= defender.ToBeHit)

If has a lot of ways to compare things (and thus, it's a pretty common way to make decisions)...

if ( this > that )  - greater than
if ( this >= that )  - greater than or equal
if ( this < that )  - less than
if ( this <= that )  - less than or equal

To compare if two things are equal is a little tricky, one way is like this...

if ( this == that)

One equal sign "sets" a variable to a value, 2 equal signs "compares" two variables/values.  The catch is that 'number as a string' problem at the beginning of the post.  Let's make 2 numbers and compare them...

var A = 1
var B = 1
if ( A == B ) {
    console.log ("true!")
}
>true!

Now, let's make one of those a string instead of a number...

var A = "1"
var B = 1
if ( A == B ) {
    console.log ("true!")
}
>true!

Well, that's still true even though one variable is a string and the other is a number.  We might not want that, we might want to only compare numbers to numbers or strings to strings.  That takes three equal signs, and while the code in the "if" will run if that's true, let's add the "else" to run code if it's false...

var A = "1"
var B = 1
if ( A = = = B ) {
    console.log ("true!")
} else {
    console.log("false!")
}
>false!

I spaced out the equals signs to show there are 3 of them, called "strict equality".

    "If" is the most common way to make a decision, but sometimes we need to "loop" or go through a series of values and check each one.  Let's say we want to look in the player's backpack and see if they have a knife.  The most common loop is "for"...

for ( counter ; comparison ; operation ) {
    do something
}

So, first we create a counter, which is a variable almost always called "i", and we set a starting value...

for ( i = 0 ; comparison ; operation ) {
    do something
}

Next we compare where we are (with our counter) to where we want to be (or the end of the loop, which in this case is the length of the player's backpack)...

for ( i = 0 ; i < backpack.length ; operation ) {
    do something
}

Why not go until i <= backpack.length?  Because the loop is always going to run the first time, so we want to stop before the length or else we'd run one time too many.
    Lastly, we need to increase our counter (otherwise we won't go forward) which is usually with the "increment" operator, which takes a variable and adds 1 to it...

for ( i = 0 ; i < backpack.length ; i++ ) {
    do something
}

And then we'd add the code to see if the backpack item we were looking at was the one we wanted.  Which I'll leave as an exercise for the reader :).


Manipulating The DOM
    Okay, I need to wrap this up because I've been typing for a few hours now!
    So far we've just looked at JavaScript itself, how do we get our JavaScript to interact with the webpage?  Well, we use the DOM, or Document Object Model.  Basically, JavaScript itself gives us a few functions to access parts of the page.
    There are 3 main functions we can use to select something on the page.  If we want to get a tag (like <p> or <div>) we'd use...

document.getElementsByTagName("p")
document.getElementsByTagName("div")

    If we want to get an element by it's class (let's say the class is "yellowtext"), we'd use...

document.getElementsByClassName("yellowtext")

    And to get an element by it's ID..

document.getElementById("id")

     We can also change the content of an element with...

element.innerHTML = new html content

    I'm actually not going to go into this in any detail, while you can access elements from JavaScript I really prefer to use a JavaScript library called jQuery which is a lot easier to use (and type) - I'll go into jQuery when I start using it on the project.


Events
    Last thing to mention, and again it's time to wrap this up - we can also listen for "events" something that the user does.  So we can listen for a "click" event and do something when the user clicks on a button, or a "mouseover" event for when the user moves the mouse over an element.  Again this is something that can be done in JavaScript, but I'm going to use jQuery for - and I'll be able to give you some concrete examples once the project gets rolling.


    Wow, that was a lot - and even though I always say I've only scratched the surface, in this case that's an understatement!  There is so very much more of JavaScript to cover - which is why it's usually discussed in something the size of a book!

    This finishes the last of my 'whirlwind' tours, next post we're going to actually make something using HTML, CSS and JavaScript.  As I've mentioned before, my recommended starting point to learn more is the w3schools site.
    Until tomorrow!



No comments:

Post a Comment