Introduction

This is the first tutorial in a series designed to teach basic JavaScript game programming. It's the spiritual successor to BASIC Computer Games, in which David H. Ahl provided source code for 100 BASIC games. Today, we would think of those games as "terminal programs", displayed using ASCII text. We will be running our games in a web browser, and while they will initially be text-based, we will quickly move into the realm of canvas graphics.

But first things first. In this tutorial, we will cover the boilerplate concepts behind all games: variables, output, input, functions, loops, and flow-of-control. Don't worry if you don't know what any of those mean -- that's what the tutorial is for. Once we have discussed these fundamentals, we'll present the code for our first game: GuessIt.

Fundamentals

All games rely on the following foundational concepts. More advanced games involve additional ideas, but every game needs these:

variables -- named buckets that hold data

output -- how we show the game to the user

input -- how we accept data from the user

functions -- how we re-use code from at different points in a program

loops -- how we perform repeated tasks efficiently

flow-of-control -- how we make the game choose one path among many

VariablesVariables are just chunks of computer memory that hold data for us. You can think of a variable as a bucket with a name. You can put things in the bucket and take them out again.

In some languages, there are different kinds of buckets for different kinds of data. Text goes in one kind of bucket, decimal numbers in another, and integers in yet another. In JavaScript, all buckets can hold anything you want. This simplifies life in some ways, and complicates it in others.

To define a new bucket, we use the 'var' keyword, followed by the name of the bucket:

var myName;

(the semicolon tells JavaScript that it has reached the end of this line of code).

Once you have defined a new bucket, you can refer to it by name elsewhere in your code. You can use operators like the equals sign to manipulate the data inside the bucket.

For example, in JavaScript, the single equals sign (=) tells the computer to take whatever is on the right hand side and put it into the thing on the left hand side:

myName = "Mark";

takes the text data inside the double quotes and sticks it in the bucket called myName.

You can combine the definition of the bucket and the assignment of its value into a single line, if you like:

var myAge = 49;

Now the variable 'myAge' has a value of 49.

Variables can hold text data, numerical data, code, graphics, sound, and any combination of these things wrapped into an 'object' (which we will cover in later tutorials).

Variables can also contain lists of data. These lists are often called "Arrays", and you create a list by enclosing the entries in square brackets ('[' and ']') and separating them by commas:

var myDogs = ["Hershey", "Koda"];

You can also break this up over multiple lines:

var myDogs = [
"Hershey",
"Koda"
];

That's a lot to remember, but don't sweat it. The most important thing is:variables are buckets that hold data.

OutputAll games need to output data to the player(s). Our first games will run on a web page, so we will use HTML for output. We will rely on the "write line" command supplied by the document in which we are running:

document.writeln("Your message goes here...");

Note that in HTML, the "string" of letters '<br>' (without quotes) is a "line break" that marks the end of a line of text. Use this to move down to the next line.

These will appear as two separate lines in the web browser. Without the line breaks, they would appear together on a single line, even though we used two different writeln statements.

InputPlayers need a way to affect the games they play, whether it's telling the dealer to "hit me" in Blackjack, or firing a weapon in Doom. In our case, we will be responding to keyboard events. To do this, we will rely on the "event listener" system supplied by the document in which we are running.

An "event" is a change in the computer environment that affects the document. This could be many things: a key press, a mouse click, a message telling the browser to resize itself. Web documents supply an "event listener" system to capture and respond to important events. To listen for a particular event, we will call the document's "addEventListener" code:

The above line tells the document to execute "...your code here..." whenever the user presses key down. Don't worry about the 'function(event)' bit -- we'll discuss that in the next section. For now, let's consider this concrete example:

This displays the message, "Someone pressed a key!" each time the user presses a key.

There are many other events to which the document can respond, like "keyup", "mousedown", "mouse", and "mousemove", just to name a few. We'll get to those when we need them. For now, "keydown" is good enough.

Sometimes, you want your game to ignore events to which it previously responded. You can accomplish this using the "removeEventListener" command:

document.removeEventListener("keydown");

This would undo the "addEventListener" we used above.

FunctionsOften, you write a chunk of a code that you want to use over and over. For example, suppose you wrote a chess program. Games of chess can last many turns. You would hope that you could write the code to play a single turn, then simply re-use that code for each subsequent turn.

Functions allow you to do this. A function is a chunk of self-contained code designed to perform a specific task. Functions often require data to complete their task, so when you define the function, you must indicate what data it's expecting as input. In JavaScript, function definitions look like this:

function(list of input data) {
// Chunk of code to execute using the input data
};

If this seems confusing, think of a function as a meat grinder: you put stuff in, you turn the crank, and something useful comes out. The "stuff you put in" is the "list of input data". The "turn the crank" bit is the "chunk of code" part. The "something useful comes out," well...we haven't covered that. It's called the 'return value'. A specific example will clear all this up. Consider a function that computes the area of a rectangle:

function(length, width) {
var area = length * width;
return area;
};

You send in a length and a width, it multiplies them together to find the area, then it 'returns' that area back to you.

Remember that addEventListener stuff? Recall that the function looked like this:

function(event) {
document.writeln("Someone pressed a key!");
}

Now you know what the 'function' is for -- that tells JavaScript what function to execute when someone presses a key. The 'event' data is passed into the function from the web browser, and it tells the function things like what key was pressed. In fact, we could change the function to display that information as follows:

Notice that this function doesn't return anything (there is no 'return' statement at the end). That's fine. Not all functions return a value. Sometimes you use them just to produce output when the crank is turned.

One last note: you can store a function inside a variable. Doing so lets you execute (or call) the function using the bucket's name. This is handy shorthand for executing code!

LoopsOften, games need to rapidly repeat a task. For example, if you are drawing a square grid, you must print multiple horizontal and vertical lines. For something like tic-tac-toe, this isn't so bad, but for a game like Go, you wouldn't want to draw every line with a new command.

Loops allow programmers to efficiently perform duplicate commands. There are several kinds of loops, all of them follow the same philosophy: the programmer defines a loop condition during which the program repeats a chunk of code over and over. The programmer follows the loop condition by the code to be repeated:

[Loop Condition Goes Here]
{
// ...code to repeat goes here
}

Notice that in JavaScript, we use curly bracers ('{' and '}') to "section off" the code that will be repeated.

JavaScript supports several different kinds of loops. We will start with just two: the 'while' loop and the 'for' loop (which is really just a 'while' loop in fancy clothes).

Clearly, this is nonsense! There is no number that equals itself plus one.

True...but remember -- in JavaScript, the '=' symbol differs from what you learned in Math. In JavaScript, it says, "takes what's on the right-hand side and put it into the thing on the left-hand side." Also remember that 'greets' is a bucket that we initially fill with the value 0. So this:

greets = greets + 1;

reads as:

"Take the value in greets (currently 0), add one to it, and place this back in the greets bucket."

So, after executing this line the first time, greets' value changes from 0 to 1.

We then hit the bottom curly brace and bounce back up to the 'while' statement, where we check the loop condition. Is the value in greets less than 5?

Yep! So we once again execute the code inside the curly braces. While doing so, we again hit the line

greets = greets + 1;

but this time, greets contains '1'. So what happens? We add one to it, and store the resulting value (2) back in greets.

Then we hit the bottom curly brace, bounce back up to the top of the loop, and check the conditions. 2 is still less than 5, so we go around again......and again......and again......and again......and finally we bounce back to the top, check the condition and see that greets is equal to 5, rather than less than 5, so the loop condition is false and we break out of the loop by instantly jumping past the last curly brace.

That might seem like a silly example: why would we want to print out the same message 5 times? So let's consider a more useful example. Remember my dogs?

Now we're using the while statement to iterate (or step through) a list of data. Notice that we use square brackets ('[' and ']') to access a single element of the list, and that the first element in the list is number 0. In other words:

myDogs[0]

contains the word "Hershey", and

myDogs[1]

contains the word "Koda".

Also note that JavaScript will tell you how long any list is when you use the ".length" accessor:

myDogs.length

is 2.

While loops are handy, but after you've written a few, you'll see that most of them fall into the following pattern:

Flow-of-ControlFinally, let's talk about "flow of control." That's just a fancy way of saying, "my game can execute one of several options at the appropriate time." For example, suppose you are making a dungeon crawler and you have AI monsters that can take one of several actions when encountering the player. You would use flow of control statements to pick one of those actions when an encounter occurs.

As with loops, there are several flavors of decision-making in JavaScript. For now, we will restrict ourselves to the "if...then" statement. Generally speaking, that structure looks like this:

If (condition 1 is true)
{
// Do this code
}
else if (condition 2 is true)
{
// Do *this* code instead
}
else if (condition 3 is true)
{
// etc.
}
// and so on for as many conditions as you like, until finally
else {
// Do this if nothing else up to this point was true.
}

Note that the triple-equals ('===') in JavaScript asks the question, "is equal to". So a line like this:

if (myDogs[i] === "Hershey")

Reads as, "if the ith element in myDogs is equal to the word Hershey".

As you can see, this will print out:

Hershey is barking.Koda is farting.

Which might seem like a fart joke, but is sadly the status quo with my black lab, who is currently practicing his "art" 6 feet from my desk.Ugh.

Conclusion

You now have all the building blocks you need to make a simple game. For our first outing, we will write "GuessIt" -- a variation on the card game Acey Ducey. In that game, you flip two cards, then place a bet as to whether a third card, when revealed, will fall between the first two. In GuessIt, we use randomly-generated numbers from 0 to 9, but otherwise, the game is identical.

Take a look at the source code. We have broken it up into two files:

definitions.js -- in which we define all the functions and variables used in the gamecommands.js -- which actually executes the commands defined in definitions.js to start the game

If you just loaded definitions.js, the game would never start, because the definitions don't do anything but fill buckets with values and functions.If you just loaded commands.js, the program would throw an error because the commands rely on the buckets defined in definitions.js.

You don't have to lay out your JavaScript programs this way -- we just did it to drive home the point that defining variables and functions is a passive activity, like setting up the game board. It doesn't actually result in the activity of playing the game itself. To do that, you have to execute the commands you created earlier.

The code for GuessIt contains a lot of comments to help you understand what we're doing at each point. Some of it repeats what we have covered here, but in a more specific context. Once you are comfortable with what it's doing, try modifying the game. Here are some suggestions:

Change the background color by using the command:document.body.style.backgroundColor = "gray"; // Or whatever common color name you want

Change the amount of starting cash given to the userChange the payout formula

Or, the biggie:Add a new eventListener when the player loses that resets her starting cash and allows her to play again