LESSON 4 - April 7, 2013

HTML5 GAME DEVELOPMENT

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

Ben W. Savage

And now the fun stuff! Thanks for being patient, but I wanted to get through some basic canvas functions before we started moving things around. You might never use lines or curves in your games, but it's ALWAYS a good idea to have that extra baggage in case you happen to need it someday. Why just learn the necessary commands and leave the rest vague? That's not the way to do things! Hey, we want to aim high and try to MASTER HTML5, not just mess around enough to scrape by!

Anyway, we'll be coming back to more advanced canvas features tomorrow, so let's just spend today messing around with the few commands we know and making objects move around the screen in funny ways.

Are we ready?

Ok, so there are three very important timer events we need to discuss that will lead us into animation. They are:

I'll let you in on a little secret and tell you that requestAnimationFrame is the most preferable of 'em all. Why? Because it makes for more fluid, less expensive animations, that's why! The other two are cool, though, and very useful, but not optimal if you have 50,000 things flying across the canvas at the same time. You may not notice it now at this stage of the game, but it's a good idea to at least learn how it works so you can implement it in future experiences. If you mess up royally, don't fret - we'll be doing another animation tutorial in the near future.

So like the Three Little Pigs, let's introduce one at a time. So fluff up your pillow, sit back and let me tell you a story.

THE THREE LITTLE TIMERS

Once upon a time there was a method called setTimeout(). He built his house out of straw and ran once and only once after the number of seconds we specified that he needed to wait.

Then along came setInterval(). He built his house out of sticks and ran an infinite number of times. We told him how much time passed between repetitions.

Finally there was requestAnimationFrame(). He built his house out of bricks, was more efficient and everyone lived happily ever after.

Oh there was a wolf in that story somewhere.

THE END

Let's use each in an example!

setTimeout(), as we saw, runs only once (unless we tweak it and have it call itself! Tee hee hee!) at an interval that we get to choose.

Ergo: setTimeout(ourFunction,timeInterval);

Our function is any block of code we decide to show after the timer runs out. The time interval is shown in milliseconds. If you don't know how milliseconds work, just remember that 1 second = 1000 milliseconds.

So riddle me this: 2000 milliseconds = ? 500 milliseconds = ? 4000 millseconds = ? 20000 milliseconds = ?

Answers at the bottom of the page.

So seeing as we need to put our curves into a function, let's go ahead and make that function right now. We'll name it playMe();

function playMe()
{
context.strokeStyle = "#44ee00";
context.moveTo(200,200);
context.bezierCurveTo(100,300,200,30,50,50);
context.stroke();
}

So instead of writing a bunch of new code, we're using what we already have and wrapping it between two curly brackets as you can see above. Great! Now all we need is to call the setTimeout function and specify our new function and time interval.

So directly above the code we just wrote, add this line:

setTimeout(playMe,3000);

Just to double-check, here's our full code.

<!doctype html>
<title> Timers n' Stuff </title>
<style>
canvas
{
background-color: #333333;
}
</style>
<canvas id = "canvas" width = "550" height = "400"></canvas>

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


window.setTimeout(playMe,3000);

function playMe()
{
context.strokeStyle = "#44ee00";
context.moveTo(200,200);
context.bezierCurveTo(100,300,200,30,50,50);
context.stroke();
}

</script>

So save it, run it in Chrome and tell me what you see.

At first....nothing! Did I trick you again?

Hey Ben, you rotten.... oh WAIT! There it is!

Yup! No tricks this time! We just need to wait the 3000 milliseconds (3 seconds) for the timer to go off.

But wait, that's sort of.... well, anticlimactic! It's like waiting for a fireworks display and only seeing one explosion. That's no fun! You'll find some places you'll want to use this, though.

But for now, let's skip on ahead to our pal, setInterval();

Let's erase our boring setTimeout and get this party started, ok?

setInterval has two values and they are basically the same as those from setTimeout except the milliseconds represent the interval of time that lapses between repetitions. So, in other words, it'll go on endlessly (unless you use clearInterval which we'll probably be taking a look at in the next animation lesson).

Say, this stuff is GRAND! Sounds like animation material to me!

So go ahead and add the following to your code where setTimeout used to be:

setInterval(playMe,500);

Note that I've changed the interval to 500 milliseconds to speed up the animation a bit.

So what happens? Nothing at first, since it needs to wait the initial half second we assigned to it, then the real fun begins! What you'll see is a curve being placed onto itself over and over again. By itself that's not too much fun, so instead of watching this repetitive mess, let's make it MOVE.

Now how the heck can we do that? Easy! We just add a few simple pieces of code.

The first thing to do is call a global variable. We'll put this underneath the var context line like so...

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

Following that, in our playMe function we need to make a couple small changes.

First we need to change the first value of our bezier curve from 100 to increment as you can see here:

context.bezierCurveTo(increment,300,200,30,50,50);

Why do we need to do that? Because that's the part we're going to be changing on each repetition of the setInterval function. Every 500 milliseconds, in other words. Now all we need to do is specify how much to change it at every interval. We do this by adding the following to the end of our playMe function code:

increment += 10;

This very important little line tells the computer we want to increase the value of increment by 10 each time we repeat the function. This could be written as increment = increment + 10, but the shortcut method may trim hours off your life in the end. I mean, would you rather spend hours of your life swimming in the ocean on a summer's day or typing stuff the long way? YOU choose!

Coincidentally, we can also do the same thing with subtraction, division and multiplication. Watch this:

increment = increment * 10; (multiplication) is the same as increment *= 10;
increment = increment / 10; (division) is the same as increment /= 10;
increment = increment - 10; (subtraction) is the same as increment -= 10;

Oh how we love easy!

So, after we add that line of code, let's save + run it.

Noooooow we're talkin'! Here's the full code in case you're not seeing anything particularly exciting:

<!doctype html>
<title> Timers n' Stuff </title>
<style>
canvas
{
background-color: #333333;
}
</style>
<canvas id = "canvas" width = "550" height = "400"></canvas>

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

var increment = 5;

window.setInterval(playMe,500);

function playMe()
{
context.strokeStyle = "#44ee00";
context.moveTo(200,200);
context.bezierCurveTo(increment,300,200,30,50,50);
context.stroke();
increment += 10;
}

</script>

Now here's the cool part: you can add an increment anywhere you want to!

Go ahead and erase everything inside the playMe function and write this instead:

context.strokeStyle = "#44ee00"; context.moveTo(200,200); context.lineTo(300,increment); context.stroke(); increment += 10;

Or try erasing everything in the playMe function once again and adding this:

context.strokeStyle = "#00ff00";
context.moveTo(200,50);
context.lineTo(increment,150);
context.lineTo(increment,150);
context.lineTo(increment,200);
context.lineTo(increment,300);
context.lineTo(increment,225);
context.lineTo(increment,300);
context.lineTo(increment,200);
context.lineTo(increment,150);
context.lineTo(increment,150);
context.lineTo(increment,50);
context.stroke();

increment += 10;
}
</script>

I mean, WHATEVER you want! Isn't this cool? I've spent many an evening just messing around with values and moving shapes across the screen. So satisfying!

So try 'em out yourself and let me see what you come up with. Go ahead and tweet me @benwhi and let me know.

The key here, if you want to become a better coder is to EXPERIMENT. A LOT! Half of your study is to read nifty tutorials like mine, but the rest is up to you and ONLY you! You've got to be the one to commit to your craft and learn it the best you can. There are quite a few good books out there, but don't let reading be your ONLY learning activity (though DO A LOT OF IT)!

Now lastly, I just want to look at the king of all timers: reqestAnimationFrame();

Why is requestAnimationFrame so cool? Well, see for yourself:

requestAnimationFrame()

As you can see from the comparisons, requestAnimationFrame is a much better choice when making animations. In fact, requestAnimationFrame is the cousin not of setInterval, but of setTimeout. What gives?? I don't want to run my timer once and only once!

Well, folks, there's a trick you might want to know:

You can sit it up so that setTimeout AND requestAimationFrame to call THEMSELVES! Deep, huh?

Let's take a look at an example:

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

var increment = 5;

requestAnimationFrame(playMe);

function playMe()
{
context.strokeStyle = "#00ff00";
context.moveTo(200,50);
context.lineTo(increment,150);
context.lineTo(increment,150);
context.lineTo(increment,200);
context.lineTo(increment,300);
context.lineTo(increment,225);
context.lineTo(increment,300);
context.lineTo(increment,200);
context.lineTo(increment,150);
context.lineTo(increment,150);
context.lineTo(increment,50);
context.stroke();
requestAnimationFrame(playMe); <----- looky here!

increment += 20;
}
</script>

Now what's happening here?

As you can see, at the bottom under context.stroke(), we added a second requestAnimationFrame() which calls itself! I don't want to get into the specifics, but keep in mind that we can do the same exact thing with setTimeout, as you can see here:

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

var increment = 5;

setTimeout(playMe);

function playMe()
{
context.strokeStyle = "#00ff00";
context.moveTo(200,50);
context.lineTo(increment,150);
context.lineTo(increment,150);
context.lineTo(increment,200);
context.lineTo(increment,300);
context.lineTo(increment,225);
context.lineTo(increment,300);
context.lineTo(increment,200);
context.lineTo(increment,150);
context.lineTo(increment,150);
context.lineTo(increment,50);
context.stroke();
setTimeout(playMe); <------ remember me?

increment += 20;
}
</script>

You might be interested in knowing how we can change the interval between repetitions in the requestAnimationFrame() method, but we'll look at that along with clearInterval() in the near future. I don't want to get things too complicated today. After three lessons dealing with the basics, we owe ourselves some fun time as well.

So in the meantime, just enjoy yourself with what we have for the time being.

That's it, lesson's over!

As always, play around and experiment with the new tools that you learn.

Tomorrow we'll deal with some new tools in the canvas which we haven't touched upon yet.

Thanks for following along! Code didn't work for you? Hate me? Are you my illegitimate child? Send input anytime!

Until tomorrow!

-Ben
@benwhi

P.S. I wanted to thank all of you for the kind words of support - I've received some super nice compliments and words of encouragement on Twitter, Newgrounds and the Html5gamedevs.com forum. Just wanted to let you know that it's greatly appreciated and more than makes up for the hours spent writing these things! So... THANKS A BUNCH!

Here's the answer key to the simple little milliseconds exercise:

Answers to milliseconds exercise:
2 seconds
.5 seconds
4 seconds
20 seconds


Onward to Lesson Five!
Back to Lesson Three
Back to Index