LESSON 15 - April 18, 2013

HTML5 GAME DEVELOPMENT

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

Ben W. Savage

Today and tomorrow we're going to introduce what happens when you move an object to the extremes of the canvas and how to handle its reaction with those extremes. In our stupid little blastoff example a couple lessons ago, we saw that once our courageous astronaut reached the top of the screen there was absolutely no hope of ever returning to earth (or the canvas at least), so we'll need to tweak a few things in order to make return possible.

BUT! Where should he return to? Or should he leave at all? We have several options, you see! So let's play around with the various options today and tomorrow and I'll let it be up to you which ones you decide to employ in your games.

Let's go back to our "spaceship" example:

<!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;
}
}
if (altitude < 0)
{
altitude = 400;
}
</script>

Go ahead and run it once more just to refresh your memory. This is simply a keyboard event-based engine which is run continuously thaks to a setInterval timer which clears the screen every frame.

Now let's add a Pac-Mac/Asteroids sort of loopy effect (or screen-wrapping to the conniosseurs) to the top of our screen in order to make it reappear on the bottom of the screen:

This is done through a simple if statement. Just one for each side. ALL we need to do is say:

If the ship goes through the top of the screen, make it appear at the bottom.

Ergo, remove this little piece of code from the bottom of your code and add it to the bottom of your drawRectangle function:


if (altitude < 0)
{
altitude = 400;
}

Now run it and let me know what happens when you reach the top of the screen. It starts at the bottom of the screen again! Brilliant! But one question, though... why did we put it in the drawRectangle function?

Well, that's because we've established our drawRectangle function as a sort of engine which continuously refreshes our window. In fact, this is somewhat comparable to the ENTER_FRAME method those of us with Actionscript backgrounds know and love.

So (and this is VEEEEERRRY IMPORTANT to grasp early on in the game):

Always remember to distinguish between things you want to do ONCE and things you want REPEATED!

ALWAYS keep a clear distinction between the two in your head. It'll help you immensely.

In this case, we want the browser to check whether our altitude value is less than zero.... not ONCE, not TWICE, but constantly! This is the reason why we stick it in the drawRectangle function: because it is powered by the setInterval timer which runs constantly and can check if altitude is less than zero constantly as well.

Go ahead and throw this same if statement outside the drawRectangle function. Doesn't work? That's because the code OUTSIDE the setInterval runs only once and can't check the value of altitude every so often. It just runs once, then stops. Make sense? Make sure you understand this concept. It's SO important!

So anyway, here we are with a ship that moves up, then loops back to the bottom of the screen. Let's try to add our looping effect to every side!

But first we'll need to make the ship move in all directions!

Let's do something first: let's place our spaceship near the middle of the canvas. It's easier to see that way.

Just go ahead and change the altitude value from this:

var altitude = 395;

to this:

var altitude = 200;

Actually, there's one more thing we can change, just to make our code more efficient:

We're hard-coding a lot of our values and that's not ok because it could lead to confusion later on. Let's create some more variables that can hold the characteristics of our ship:

var shipWidth = 50; var shipHeight = 50

Go ahead and add these two variables at the top, under the altitude variable.

Now let's go ahead and substitute these new variables with the arguments in the code. The new, more polished version of your code should look like this:

<!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 = 200;

var shipWidth = 50;
var shipHeight = 50;

window.setInterval(drawRectangle,24);

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

if (altitude < 0)
{
altitude = 400;
}

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

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

A little bit longer, but much nicer!

But there's still something else we should change: we don't want our ship just to move left and right, do we? Let's add some real run and make it move left and right as well!

This will require another variable and I'll call it latitude.

I know I'm skewering physics AND cartography in one fell swoop with these names, but they're only to help us learn. We'll be looking at MUCH better ways of dealing with boundaries and other stuff tomorrow. Enjoy these while you create them, but realize that you're going to be doing them BETTER tomorrow. Today let's just have fun.

So add latitude, give it a value of 275 (half the width of the canvas), then plug it into your fillRect X value.

As not to confuse you, here are the new contents of our <script> tags:

<script>

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

var altitude = 200;
var latitude = 275;

var shipWidth = 50;
var shipHeight = 50

window.setInterval(drawRectangle,24);

function drawRectangle()
{
context.clearRect(0,0,canvas.width,canvas.height);
context.fillStyle = "#44ff11";
context.fillRect(latitude - shipWidth,altitude,shipWidth,shipHeight);

if (altitude < 0)
{
altitude = 400;
}

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

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

Ok, with that done, let's go ahead and make our ship move in all four directions! Sound fun? It IS!

Here's how ya do it:

Just go to your keyDown function and add these 3 if statements:

if (event.keyCode == "40")
{
altitude -= -10;
}

if (event.keyCode == "37")
{
latitude += -10;
}
if (event.keyCode == "39")
{
latitude += 10;
}

The first one checks for keyCode 40 (down arrow) and increases altitude by a NEGATIVE 10 each time. This makes the value decrease each time and cause the ship top go lower.

The first one checks for keyCode 37 (left arrow) and increases latitude by a NEGATIVE 10 each time. This makes the value decrease each time and cause the ship to go further left.

The last one checks for keyCode 39 (right arrow) and increases latitude by a POSITIVE 10 each time. This makes the value increase each time and cause the ship to go further right.

Got it?

Kinda choppy, I know, and you can't really make your rectangle move diagonally without mashing, which really stinks. But in the next few lessons we'll look at better ways to implement this. But for now it's moving and that's GREAT!

But we still haven't set the looping for all four sides! Let's go do that now. Add the following code at the bottom of your drawRectangle function:

else if (altitude > 400)
{
altitude = 0;
}
if (latitude > 550)
{
latitude = 0;
}
else if (latitude < 0)
{
latitude = 550;
}

Save it, run it and watch your rectangle fly all across the screen! It never stops! It just loops and loops and loops any way you launch it! Guess it's not so much of a blastoff anymore. You can go ahead and change the title any time.

So far so good, but what else can we do with our stage boundaries? What if we wanted to keep our ship within the boundaries of the canvas as if it were trapped in an invisible glass box?

It's amazingly easy to do, but I don't want to take this lesson TOO far since we're not learning these methods in the most optimized way. I just wanted to introduce the CONCEPT of screen wrapping and boundaries. Tomorrow we'll learn things the most optimized way and you'll be able to move objects all over the place effortlessly!

And that does it for today! Short, but sweet!

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 Sixteen!
Back to Lesson Fourteen!
Back to Index