LESSON 13 - April 16, 2013

HTML5 GAME DEVELOPMENT

Operation C.A.N.T (Canvas Ain't No Thang) LESSON # 13

Ben W. Savage

Good morning, world! I hope all you're ready for this next one, because it's going to be crucial for controlling the characters in your games. The topic for today is keyboard events and we'll be going over the two types that you have available to you in HTML5, namely: keydown and keyup.

Let's start with keydown, shall we not?

Now the standard event listener formula applies here as well. This is the format:

window.addEventListener("keydown",onKeyDown,false);

By now you should have a good grasp of what all this code means. If not, take a look back at previous lessons where I discuss event listeners, then come meet me here again.

<!doctype html>
<title>EVENT LISTENERS</title>
<canvas id = "canvas" width = "550" height = "400"></canvas>
<style>
canvas
{
background-color: #dddddd;
}
</style>

<script>

var theCanvas = document.getElementById("canvas");
var context = theCanvas.getContext("2d");

context.fillStyle = "#0055cc";
context.arc(100,100,30,0,6.294,false);
context.fill();

var increment = 1.8;
var arcRadius = 10;

window.addEventListener("keydown",onKeyDown,false);

function onKeyDown(event)
{
context.fillStyle = "#5500ee";
context.arc(100,100,arcRadius,0,6.294,false);
context.fill();
arcRadius += increment;
}

</script>

Go ahead and punch this into your computer-machines or whatever kids call them today, and watch in awe as the circle spreads across the screen when you hold down any key. Note that the listener must be attached to the WINDOW, not the canvas for this one since the canvas itself doesn't receive the keyboard presses.

So let's do something even neater! Let's add a keyup listener to our window that changes our circle to green after they key has been depressed, then lifted.

So modify your code in the script tag until it looks like what I have here:

<script>

var theCanvas = document.getElementById("canvas");
var context = theCanvas.getContext("2d");

context.fillStyle = "#0055cc";
context.arc(100,100,30,0,6.294,false);
context.fill();

var increment = 1.8;
var arcRadius = 10;

window.addEventListener("keydown",onKeyDown,false);
window.addEventListener("keyup",onKeyUp,false);

function onKeyDown(event)
{
context.fillStyle = "#5500ee";
context.arc(100,100,arcRadius,0,6.294,false);
context.fill();
arcRadius += increment;
}
function onKeyUp(event)
{
context.fillStyle = "#ff0000";
context.arc(100,100,arcRadius,0,6.294,false);
context.fill();
arcRadius += increment;
}

Contrary to popular belief amongst beginners, keyup does NOT work right when the window loads and the computer notices that none of the keys have been pressed. Imagine what hackers could do to your computer if THAT were an option! No, our friend keyup comes into action AFTER a keydown has been made. In other words, it's a reaction to our keydown. The same thing applied to our mousedown and mouseup listeners if you were paying attention!

Now this stuff of course can be applied to character movement, as you'll see. Very soon we'll be setting up a little game in which you control your character with keyup and keydown.

But one thing we need to specify first:

Sure, pressing down ANY key is fine and dandy, but how do I specify the key I want to use??

Well, let me sing you a song about keyCode...

No...on second thought I won't sing you a song about that, but I'll sure tell you how it works!

Did you know that every key that you can press has a corresponding keyCode? Yes, everything from the arrow keys to the CTRL keys, to f11 have keyCodes assigned to them. Unless you have an AMAZING memory, or unless you use the same ones most of the time and only need to memorize a few (like me), you're going to need to hunt around on the internet to find these guys. But they're not hard to find at all. In fact, I'll be nice and give you a link right here:

Nice link: http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes

Now that we can find the code for any key we want to press, let's look for a moment at how to implement them!

To get specific about which key we're dealing with, we use an if statement inside our onKeyDown and onKeyUp functions.

Here's what it looks like:

<script>

var theCanvas = document.getElementById("canvas");
var context = theCanvas.getContext("2d");

context.fillStyle = "#0055cc";
context.arc(100,100,30,0,6.294,false);
context.fill();

var increment = 1.8;
var arcRadius = 10;

window.addEventListener("keydown",onKeyDown,false);
window.addEventListener("keyup",onKeyUp,false);

function onKeyDown(event)
{
context.fillStyle = "#5500ee";
context.arc(100,100,arcRadius,0,6.294,false);
context.fill();

if (event.keyCode == "38")
{
arcRadius += increment;
}
else
{
arcRadius += 0;
}
}

function onKeyUp(event)
{
if (event.keyCode == "38")
{
context.fillStyle = "#ff0000";
context.arc(100,100,arcRadius,0,6.294,false);
context.fill();
arcRadius += increment;
}
else
{
arcRadius += 0;
}
}

</script>

Now this may look complicated, but it's not that bad at all. Here we've added a conditional statement (if/else) to the keydown as well as to the keyup functions. Here's how they work:

function onKeyDown(event)
{
context.fillStyle = "#5500ee"; <----- here's our initial rectangle state.
context.arc(100,100,arcRadius,0,6.294,false);
context.fill();

if (event.keyCode == "38") <--- here's our if statement. It asks if the keyCode is indeed 38 (up arrow)
{

arcRadius += increment; <--- and this is what happens if the key being pressed IS 38 (up arrow).
}
else <--- here's our else statement which gives an alternative course of action.
{
arcRadius += 0; <--- This is our alternative. We set the incrementation to 0 making our circle
} stay the same if any other key is pressed.
}

And you'll also notice that we've done the same thing with the keyup listener too!

Say we wanted to listen for two keys? Say, for example we wanted either of two keys to do the work. How would we go about doing that? Well, all we'd need to do is change our if statement around in the following way:


if (event.keyCode == "38" || event.keyCode == "39")
{
arcRadius += increment;
}

See what I did there? with two pipes || I can specify "or" in my conditional statements. This will add the increment if I press EITHER the "up" key (key code 38) OR the "down" key (key code 39).

So that, in a nutshell, is how keyup and keydown work. Tomorrow for our review class I'll be making three mini projects like I did last week. One of these will certainly be dealing with keyboard events.

But experiment, dammit! The world is your oyster when you can start using these in your code!

That's really all I have to say about keyboard and mouse listeners. We'll also be taking a look at touch-based listeners when we get into our tutorial (still pretty far away) on mobile games. But before we end this two-part event listener lesson with another exercise just to reinforce what we've talked about in the past few days:

Go ahead and run this code and tell me what you think:


<!doctype html>
<title>BLASTOFF!</title>
<canvas id = "canvas" width = "550" height = "400"></canvas>
<style>
canvas
{
background-color: #dddddd;
}
</style>

<script>

var theCanvas = document.getElementById("canvas");
var context = theCanvas.getContext("2d");

var altitude = 395;

window.setInterval(drawRectangle,24);

function drawRectangle()
{
context.clearRect(0,0,canvas.width,canvas.height);
context.fillStyle = "#44ff11";
context.fillRect(canvas.width/2 - 25,altitude,50,50);
}

window.addEventListener("keydown",onKeyDown,false);

function onKeyDown(event)
{
if (event.keyCode == "38")
{
altitude -= 10;
}
}

</script>

It may look a bit daunting, but this is all code you've worked with before, we've just combined a few things in new ways.

First off, look at the setInterval() timer we add to our canvas. As you can see, it calls a function drawRectangle repeatedly at a frame rate of 100 milliseconds (one-tenth of a second), hence the 100 as the second argument.

In our drawRectangle function we first call a clearRect() which we saw erases everything on our canvas. This, in collaboration with our setInterval timer, is a SUPER powerful tool for animation and we'll be seeing it a lot more in future lessons. So our rectangle is being called every 100 milliseconds, it is light green and its starting point is at the bottom-center of the screen. How did we find this location? We plugged in canvas.width / 2 - 25.

Ok, the canvas.width / 2 is pretty self-explanatory: just half the width of the canvas, but what about the -25 part? Well, as you know by now, our rectangles are added to the canvas by their TOP-LEFT corners, so we need to subtract half of our rectangle's width from our canvas.width / 2 in order to REALLY find the center point in the canvas. Get used to doing this a lot! In more wordy cases, you might want to save this info in a variable, but here we'll just hard code it for simplicity's sake.

So that keeps our rectangle dead center. But to have the animation become playable, we need to attach a listener that will check for keyboard events! Hence we employ a keydown listener and attach it to our window. We've chosen a keyCode of 38 (up arrow key) and have told the computer to increase our ship's altitude (well, technically DECREASE our altitude value) for as long as the up arrow key is being held down. The altitude value was, of course, plugged into the rectangle's Y value which, when lowered, causes the rectangle to move upwards along the Y axis.

So basically all this code does is launch a rectangle (our make-believe spaceship) into the air and off the canvas, after which it's gone FOREVER. Congratulations, some of those astronauts had families, you insensitive person! If you feel horrible about standing a crew of astronauts in space, just reload the page and the "ship" will be back on the launch platform once again. You saved the day!

Even though this is a simplistic example, it's kinda GAMEY, huh? With a ice background and an image of a spacship, this could start to look interesting! We're starting to do things that could be used in real games now! Hurrah! Worth the wait?

That does it for today, folks! Tomorrow we review, then the following day we'll look at screen boundaries.

So stay tuned and I hope you enjoyed! As always, thanks for following along! Code didn't work for you? Hate me? Are you my illegitimate child? Send input anytime!

Until tomorrow!

-Ben
@benwhi
Onward to Lesson Fourteen!
Back to Lesson Twelve!
Back to Index