As we saw two lessons ago, we were able to increase the velocity of our rectangle by constantly adding a small value to our VX and VY values. If you're just starting here, and you have no clue what a VX or VY value is, I suggest you go back and check out lessons 15-18 first. Since we're getting into more complex stuff and not just individual features of the canvas, you're going to need to have a solid understanding of the basics in these lessons. So take the time to do some brushing up before pouncing on this stuff. It'll save you a lot of time!

So AX and AY work just fine for accelerating something, and we can also use these values to slow down our objects by applying negative values to them (which will eventually bring the VX and VY to their opposite value if we continue them), but how about something external applied to the movement of the objects that brings their speed to a grinding halt?

Such a thing is called friction (and it's great for ice worlds!).

To see friction in action, check out my silly Flash game Penguin Hockey.

Once you get the hang of it, you'll see that the fish slides across the ice until it's eventually stopped by friction. Note that had I applied a negative acceleration it would have eventually started moving backwards and going in the opposite direction.

Here's an example of friction in HTML5, on the other hand.

<!doctype html>

<title>FRICTION</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 rectX = 100;

var rectY = 100;

var rectWidth = 50;

var rectHeight = 50;

var VX = 3;

var VY = 3;

//var AX = .02;

//var AY = .02;

var friction = .95;

window.setInterval(drawRectangle,30);

function drawRectangle()

{

context.clearRect(0,0,canvas.width,canvas.height);

context.fillStyle = "#44ff11";

context.fillRect(rectX,rectY,rectWidth,rectHeight);

rectX += VX;

rectY += VY;

//VX += AX;

//VY += AY;

VX *= friction;

VY *= friction;

console.log(rectX,rectY);

if (rectX > canvas.width)

{

rectX = 0;

}

else if (rectX < 0 - rectWidth)

{

rectX = canvas.width - rectWidth;

}

if (rectY < 0)

{

rectY = canvas.height;

}

else if (rectY - rectHeight > canvas.height)

{

rectY = 0;

}

}

</script>

<title>FRICTION</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 rectX = 100;

var rectY = 100;

var rectWidth = 50;

var rectHeight = 50;

var VX = 3;

var VY = 3;

//var AX = .02;

//var AY = .02;

var friction = .95;

window.setInterval(drawRectangle,30);

function drawRectangle()

{

context.clearRect(0,0,canvas.width,canvas.height);

context.fillStyle = "#44ff11";

context.fillRect(rectX,rectY,rectWidth,rectHeight);

rectX += VX;

rectY += VY;

//VX += AX;

//VY += AY;

VX *= friction;

VY *= friction;

console.log(rectX,rectY);

if (rectX > canvas.width)

{

rectX = 0;

}

else if (rectX < 0 - rectWidth)

{

rectX = canvas.width - rectWidth;

}

if (rectY < 0)

{

rectY = canvas.height;

}

else if (rectY - rectHeight > canvas.height)

{

rectY = 0;

}

}

</script>

Here you can see that the VX and VY values are being mutilplied constanly by something a little less than 1. This drags the value lower and lower until it's motionless.You can fool around with this value to get the effect you like. Just don't overdo it, because you might kill/not see the effect if the values are too high or low.

If you're making an ice world, what you can do is this:

Let's say you're moving your character with the arrow keys, and he's running across the canvas merrily. As we've seen in our lessons on velocity, once you release the arrow key, the character stops abruptly because we've established that VX (or VY) = 0 in our keyup handler and that brings our rectangle to a crashing halt. All we need to do, instead, is implement it in such a way that friction is applied at that moment. Either way, the rectangle will come to a stop, but with friction applied, it looks a whole lot "icier".

You can also apply friction to other stuff like alpha if you want to get all fancy.

Just set your code up in such a way that something triggers the alpha value. This can also be adjusted to your tastes.

Here's a little example of this in action:

<!doctype html>

<title>FRICTION APPLIED TO ALPHA VALUES</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 rectX = 100;

var rectY = 100;

var rectWidth = 50;

var rectHeight = 50;

var VX = 3;

var VY = 3;

var applyFriction = false;

var friction = .95;

window.setInterval(drawRectangle,30);

window.addEventListener("click",onMouseDown,false);

function onMouseDown()

{

applyFriction = true;

}

function drawRectangle()

{

context.clearRect(0,0,canvas.width,canvas.height);

context.fillStyle = "#44ff11";

context.fillRect(rectX,rectY,rectWidth,rectHeight);

rectX += VX;

rectY += VY;

if (applyFriction == true)

{

context.globalAlpha *= friction;

}

}

</script>

<title>FRICTION APPLIED TO ALPHA VALUES</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 rectX = 100;

var rectY = 100;

var rectWidth = 50;

var rectHeight = 50;

var VX = 3;

var VY = 3;

var applyFriction = false;

var friction = .95;

window.setInterval(drawRectangle,30);

window.addEventListener("click",onMouseDown,false);

function onMouseDown()

{

applyFriction = true;

}

function drawRectangle()

{

context.clearRect(0,0,canvas.width,canvas.height);

context.fillStyle = "#44ff11";

context.fillRect(rectX,rectY,rectWidth,rectHeight);

rectX += VX;

rectY += VY;

if (applyFriction == true)

{

context.globalAlpha *= friction;

}

}

</script>

As you can see here I've eliminated the whole screen-wrapping thing for brevity's sake and have added a few things to the mix.

First off, I've made a variable called applyFriction and set it to false. After that I added an event listener to our window which detects clicks and I've called it onMouseDown. Then, in our onMouseDown handler, I've set applyFriction to true. Lastly, in our drawRectangle function, I created an if statement that says:

if (applyFriction == true)

{

context.globalAlpha *= friction;

}

{

context.globalAlpha *= friction;

}

and that fades our rectangle away to nothing. Go on and try it out with other stuff. Remember that this is simply the slow peeling away of something's original value. Any ideas on what else you could peel away?

Well, I'll tell ya: the width and height of something, the rotation of something, the x and y values of something, you name it! All you need to have in place is a gradual resting point which can equal 0 (or something else if you want to get creative, but I'll leave that up to you!).

Now it looks like we've got some extra space here, so I guess I'll introduce sine and cosine a minute and tell you how to set your VX and VY values to a specific angle instead of using the less precise VX and VY values on their own. This is just an introduction, though. I'll be covering this stuff in greater depth next time.

This is really very simple because Javascript has values automatically plugged into it which do all the math-y stuff for you. As you might have discovered already through your adventures with Javascript, along with Math.random and Math.floor which we've already seen, there are also things like Math.cos, Math.sin and Math.tan (among many other mathematics-based tools).

What we need is to determine an ANGLE and a SPEED to get these things working. The rest will be determined with Math.cos and Math.sin for this example.

So, as you'll see, VX and VY become a little more roundabout than just plugging in values directly to it. They are now the result of a simple formula, namely:

VX = Math.cos(angle) * speed;

VY = Math.sin(angle) * speed;

Now the key thing to remember for this particular formula is that the COS value is connected to the X axis and the SIN value is connected to the Y axis. This will be clearer next time, but for now, they're just elements of a formula we need for setting our velocity to a specific angle.

Now as you can see, we need to find the cos and sin of our angle. Now this ain't no angle in DEGREES, but one in RADIANS which is the preferred unit of angles in Javascript and such. If you recall from one of our earlier lessons, it's really only important to know that one full circle (360 degrees) is equal to 6.28 radians, which is 3.14 (PI, of course), which consqeuently equals 1/2 a circle. A quarter circle would be 1/2 PI and three quarters of the way around the circle is 1 and a half PI. If you're really interested in finding a precise angle, you can use this formula:

radians = degrees * Math.PI / 180.

But if you're making games and want to make your objects move at approximate angles, it's prefectly normal to do so with radians. We do the same thing in our heads with angles! How many people can really have a clear idea of 213 degrees without referring to something like 180 or 360 as a reference point in their head first?

One important thing to note is that our degree/raidan references START at 3 o'clock, then move clockwise. So, in other words, 6.14 radians = 3 o'clock (360 degrees), 3.14 radians = 9 o'clock (180 degrees), etc.

Now let's start off simple and say we want to move our objects at a 0 radians (straight forward to the right).

We take our value in radians and plug it into the formula like so:

VX = Math.cos(0) * speed;

VY = Math.sin(0) * speed;

We then assign a speed value, which was the same thing our VX and VY used to stand for. In this case we'll use 4.

So:

VX = Math.cos(0) * 4;

VY = Math.sin(0) * 4;

And by plugging these figures into our code, we come up with a movement that goes straight forward to the right.

Therefore the content of our script tags becomes:

<script>

var theCanvas = document.getElementById("canvas");

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

var rectX = 100;

var rectY = 100;

var angle = 0;

var speed = 4;

var rectWidth = 50;

var rectHeight = 50;

var VX = Math.cos(angle) * speed;

var VY = Math.sin(angle) * speed;

window.setInterval(drawRectangle,30);

window.addEventListener("click",onMouseDown,false);

function drawRectangle()

{

context.clearRect(0,0,canvas.width,canvas.height);

context.fillStyle = "#44ff11";

context.fillRect(rectX,rectY,rectWidth,rectHeight);

rectX += VX;

rectY += VY;

}

</script>

And that's our rectangle moving at 4 pixels per iteration straight to the right.

Note that I've set values to our angle and speed instead of hard-coding them in like before.

But that was easy, let's try a different one. Sayyyyy, 5.11 radians. Where do you suppose THAT will aim us?

Punch 5.11 into your angle variable, run it, and let me know what comes out!

Aha! It goes up and slightly to the right!

Now try 1.87.

And it goes down and to the left! Cool!

Next time we'll discover a whole host of things you can do with sine and cosine. But in the meantime, sit tight with that, doodle around with some friction and send your objects off in different angles. We'll get into the nitty gritty next time.

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!

See ya next week!

-Ben

@benwhi

Onward to Lesson Twenty!

Back to Lesson Eighteen!

Back to Index