LESSON 3 - April 6, 2013

HTML5 GAME DEVELOPMENT

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

Ben W. Savage

So how's the weather in your neck of the woods? Here in New York it's FREEZING!
UPDATE: (This sentence was written on Thursday. Lo and behold it's a beautiful, sunny day today).

Today we're going to talk about lines and arcs and stuff. As you may know, a line is created by marking a starting point and an end point. When you draw a pretty picture on a piece of paper, you also have a start point and an end point for every stroke that you draw. When you write me that HUGE check for $10,000, you have a start point when your pen touches the check and an end point when you lift the pen from the check.

Same thing in canvas! You need to specify where the line begins and where the line ends in order for the computer to know where to put your line. And let's not forget that in HTML5 a line means a STRAIGHT line, not a curved one. We'll see curves in a bit.

So, since we've already learned how to specify the stroke style (see code in lesson 2), we just need to draw the line. Easy, huh?

Hell yeah it is!

But first...and don't forget this, you need to add a moveTo() method to specify your starting point. moveTo(), in fact, is like moving your hand while holding a pen, but not drawing anything. You basically move the pen from one spot to another. So, don't forget to move to your starting point before drawing any lines. After that, you can use the lineTo() method to draw lines anywhere you wish on the canvas! Both moveTo() and lineTo() take the 2 values: x and y.

So give it a try, wont'cha? Punch in this code, save it, run it, and tell me what pops up! Don't forget to write context a gazillion times!

<!doctype html>
<title> Drawing a mystery shape </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");

context.strokeStyle = "#00ff00";
context.moveTo(200,50);
context.lineTo(250,150);
context.lineTo(350,150);
context.lineTo(250,200);
context.lineTo(300,300);
context.lineTo(200,225);
context.lineTo(100,300);
context.lineTo(150,200);
context.lineTo(50,150);
context.lineTo(150,150);
context.lineTo(200,50);


</script>

Wait just a second! Hey, nothing hapened!

That's right, because I TRICKED you! Muahahah! Every time you draw a line, you need to end it with THIS:

context.stroke();

This tells the computer: "Ok, I'm finished drawing this line. Now it's your turn to do something with this information." And the computer, obediently, will draw the lines you plotted out.

So go ahead and add that to your code. This will be your new and improved code:

<!doctype html>
<title> Drawing a mystery shape</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");

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

</script>

Hey, it's a star! That's right, Mario would be proud! You've made your very first drawing in HTML5! Now take some time to mess around with these commands and see what you come up with. If you make something cool, go ahead an tweet it over to me @benwhi I'd love to take a look! Just don't forget to add the context.stroke() at the end!

Also, don't forget that you can change the color of the line by just changing the strokeStyle value to a different hexadecimal value.

Now, let's take a look at a couple more line features before we move on to curves.

You've probably noticed something about your lines after having drawn 200 of them...they're all the same width! How do resolve this predicament? With lineWidth, of course!

Just plug this line of code under the strokeStyle and you'll find yourself with a line 15 pixels thick!

lineWidth = 15;

Now what about the ending of the line? What if I want it to be rounded? (Don't forget to put the value between quotation marks).

lineCap = "round";

Amazing! The tip of the line just became rounded! What other options do I have?

There are 3 options for lineCap and they are: "round", "butt" and "square". "Butt" is the default. "Square" adds a small rectangle which is half the width of your line to the end of your line.

Now what if I want the connecting parts of the line a different way? (Again, don't forget the quotes).

lineJoin = "round";

Whoopie! What options do I have for this?

Again, you have three options for the joint created at the junction of line segments: "miter", "bevel" and "round". "Miter" is the default and it makes the lines come to a nice point. "Bevel" draws a diagonal edge to your line joints. "Round" is what happens when to the end of a pencil when you write with it for too long.

I'm rushing through these, because they're something that you'll learn better if you just experiment with them yourself. Sometimes, like in this case, theory isn't too helpful! Just have fun with 'em!

There are a couple of things I've skipped by, but we'll get to everything sooner or later. But I know all of ya are craving ACTION. And ACTION is what I'm gonna give ya.... tomorrow! First we've got to finish talking about curves, though! Patience, Jedi!

There are four types of curved lines in canvas. They are:

  1. arc()
  2. arcTo()
  3. bezierCurveTo()
  4. quadraticCurveTo()

As for arcTo(), you can just chuck that one! We don't need it because everything that arcTo() can do can be done with good old simple arc(). Simplicity, people!

So, what are the remaining three and how do they work?

arc() has six values and they are: arc(x,y,radius,startAngle,endAngle,counter-clockwise)

The x and y values obviously correspond to the point where the arc is drawn. The radius is the radius of the imaginary circle we're going to wrap the arc around. The start and end angles are little tricky at first, but not too tricky:

You're going to find, if you haven't come across these before, that Javascript doesn't use degrees a whole heck of a lot! In fact, the preferred choice for Javascript is radians! Huh? What in the Sam Hill is a radian?? I could get into the mathematical reasoning behind a radian, but I won't because it's not essential to know the mechanics behind it for developing your games in HTML5. If you're interested in learning a lot of GREAT information about this stuff (and a lot of other stuff that we'll be covering in these tutorials), go check out the excellent resource by Keith Peters and Billy Lamberta: "Foundation HTML5 Animation with Javascript: Making Things Move!". When I make my Flash games, I still reference it often. Make the HTML5 version your holy book. Can't praise it enough!

You can buy it right here. Cheap too! Note the votes, by the way: I'm not making this stuff up!

Anyway, to make a long story short, the start angle and end angle values are in radians! Now you could approximate and make an educated guess keeping in mind that a full circle (360 degrees) is 6.28 radians, which is double PI (3.14 - remember that from high school math?) OR you could use this little formula in your code... ready? Here's another occasion to don that memory hat of yours:

YE OLDE DEGREES TO RADIANS FORMULA:

Radians = degrees * Math.PI / 180

Got it? I feel a song coming on, don't you? Let's take a radian value and plug it in there just to check. We said that a full, 360 degree loop around the circle is 6.28/(PI times 2) radians. So let's try to plug 180 degrees into our formula and see what that comes out to in radians:

So radians = 180 * 3.14 / 180.

Hmmm... 180 * 3.14 = 565.2 < ---- I used a calculator, of course!

And 565.2 / 180 = 3.14 radians!

Hey, it worked! But that was an easy one....let's try something a little less obvious say, 30 degrees....

So 30 * 3.14 / 180.

Hmmm... 30 * 3.14 = 94.2 < ---- Yup, used one here too!

And 94.2 / 180 = 0.523333333333 radians!

But let's play it safe and round off to .523, ok?

Got it? Not that difficult, huh? We'll be seeing radians again, so don't worry if it all didn't sink in. For now use a shortcut and think that 6.28 radians = a full trip around the circumference of the circle = 360 degrees, a half trip is 3.14 radians = 180 degrees, a quarter trip is 1.57 radians = 90 degrees, etc. etc.

So all that roundabout was to explain that the fourth and fifth values in arc() are the starting point in the circle you draw and the end point in the circle you're going to draw. Keep in mind that when you draw your circle, you will always start from the 3 o'clock position.

The last value is pretty straightforward - it's called "counterclockwise" and if you set it to false, it draws your circle in clockwise manner. So to sum up this final value of our arc() method: false = clockwise and true = counterclockwise.

So now that we know how to set values for arc(), let's begin drawing some arcs!

Here's the formula once again for reference:

arc(x,y,radius,startAngle,endAngle,counterclockwise)

Now let's return to our code and add the following lines to our code:

context.strokeStyle = "#00ff00";
context.arc(200,200,50,0,3.14,false);

making it:

<!doctype html>
<title> Arcs are rad. </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");

context.strokeStyle = "#00ff00";
context.arc(200,200,50,0,3.14,false);

</script>

Ok? Are you sure you want to run it? D'OH!!!! What did you forget???

context.stroke(); <---- DON'T FORGET ME, DAMMIT!

So our FINAL code is:

<!doctype html>
<title> Yay, I didn't forget stroke! </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");

context.strokeStyle = "#00ff00";
context.arc(200,200,50,0,3.14,false);
context.stroke();

</script>

And that will draw a lovely green semicircle starting at three o'clock and ending at nine o'clock. Draw a couple of these until you're used to them. I'll be right here when you get back. Try different widths and colors too.

Now, the last two curve methods we mentioned were:

quadraticCurveTo()

bezierCurveTo()

Which are basically the same deal, except you have two control points to mess around with in the bezier curve variant. Our formulas are:

quadraticCurveTo(control point1 X,control point1 Y, X, Y);
bezierCurveTo(control point1 X,control point1 Y, control point2 X,control point2 Y,X, Y);

A control point is a point which the curve wraps around on its way to both end points. Maybe this is a vague example, but you know that game "Plinko" on The Price is Right? You know how the plinko chip bounces off all those pointy triangles as it falls? Imagine dropping a long piece of string instead of a Plinko chip. The string would rest on certain triangles and the resulting curves it has will be shaped by where it lands on the triangles, right? Well, the triangular points in Plinko would be the control points for our curves! The curve wraps around these points just like the string would wrap around the triangles in the game of Plinko. I'm sure there's a better, less obscure example out there, but my simple mind can't conjure one up right now.

So if that example totally sucked for you, let's draw a couple curves and try to see it visually. Again, remember, the best way to learn these things is to practice them! It's all very abstract and visual, so your computer and your eyes would do a much better job of explaining a quadratic curve than I could!

So erase the code between the tags and add this instead:

context.strokeStyle = "#44ee00";
context.moveTo(200,200);
context.quadraticCurveTo(100,300,50,50);
context.stroke();

Now let's observe this curve a bit:

-We told the computer to move to the point 200 x and 200 y.
-We specified that our control point is at 100 x and 300 y.
-We set our destination point to 50 x and 50 y.

So as you see, the curve "wraps around" the 100 x 300 y point before curving upward and ending at 50 x and 50 y. Not too difficult, right? I'd say with a bit of experimentation, you'll figure these out if they're still a little vague.

Now, for completion's sake, let's do an example of a bezier curve. What's the difference? It has two control points and is "curvier" than a quadratic curve. So if you're into curves, these are right up your alley!

Erase all the stuff between the <script></script> tags once again and add this bad boy:

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

And it should be pretty much what you expect it to be. Piece of cake, right? Experiment around with a couple more examples and I'll see ya tomorrow bright + early!

Tomorrow we'll start animating stuff, so don't miss that one!

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 Four!
Back to Lesson Two
Back to Index