Friday, April 30, 2010

Moving in Canvas

‹prev| My Chain | next›

Tonight, I would like to play about with the <canvas> tag a bit. Ultimately I want to hook it up to fab.js. The <canvas> should represent where my character is and where others are. Tonight, I'll settle for representing where I am on the <canvas>.

First up, I need a <canvas>:
 <body onload="init()">
<canvas id="canvas" width="500" height="500"></canvas>
</body>
I will use a 500x500 grid to keep the math simple—at least to start. Next I need to define that init() function:
function init() {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

var me = {x:250, y:250};

draw(ctx, me);
}
I grab the <canvas> element and get a 2-D context in it. I have no idea what you can do differently with a 3-D context, nor do I need to know for this experiment. I then define me as being right in the middle of the 500x500 square. With a <canvas> context and me, I am ready to draw:
function draw(ctx, me) {
ctx.beginPath();

// clear drawing area
ctx.clearRect(0,0,500,500);
ctx.fillStyle = '#ffffff';
ctx.strokeStyle = '#000000';
ctx.fillRect(0,0,500,500);

// draw me and fill me in
ctx.rect(me.x,me.y,5,5);

ctx.fillStyle = '#000000';
ctx.fill();

ctx.stroke();

ctx.closePath();
}
The beginPath() call sets the coordinate system back to the top-left of the canvas element. Then I clear the rectangle (good for subsequent calls especially), set the background color to white and the foreground color to black. I fill the <canvas> with the background color then I draw me as a 5x5 box at the specified coordinates.

Loading this in the browser, I get:


Nice off to a good start.

Now I need to animate this, which means call the draw function again at the end of itself:
function draw(ctx, me) {
// draw the canvas and me
setTimeout(function(){draw(ctx, {x:me.x+1,y:me.y})}, 25);
}
Now, when I reload, I move off to the right of the screen:


To actually move, I set handlers on the document to capture keyup and keydown events. When a keydown happens, I start to move (the direction should depend on which arrow key is pressed). When a keyup occurs, I should stop moving:
var direction = null;

document.onkeydown = function(ev) {
switch(ev.keyCode) {
case left:
case up:
case right:
case down:
direction = ev.keyCode;
break;

default:
direction = null;
break;
}

if (direction) return false;
}

document.onkeyup = function(ev) {
direction = null;
}
This is something of a hack, putting the event handler on the entire document and setting a global direction variable. I can live with the hack for now as I am just playing...

The values of up, down, left and right are the key codes that would be sent if they are pressed:
// key codes / directions
var left = 37,
up = 38,
right = 39,
down = 40;
With a global direction representing where I am, I can use that to update my coordinates in draw() accordingly:
function draw(ctx, me) {
// clear the canvas and draw my current position

var x_diff = 0;
if (direction == left) x_diff = -1;
if (direction == right) x_diff = 1;

var y_diff = 0;
if (direction == down) y_diff = 1;
if (direction == up) y_diff = -1;

var me_next = {
x: me.x+x_diff,
y: me.y+y_diff
};

setTimeout(function(){draw(ctx, me_next)}, 25);
}
Just like that, I can move myself about the <canvas>!

Once last thing—I can actually move outside of the canvas as-is. To prevent that, I add a check to the me_next computation:
  var me_next = {
x: (me.x+x_diff > 0 && me.x+x_diff < 500) ? me.x+x_diff : me.x,
y: (me.y+y_diff > 0 && me.y+y_diff < 500) ? me.y+y_diff : me.y
};
You can even try this yourself (complete source code).

That's a good stopping point for tonight. Tomorrow, I will add mouse interaction and send to fab.js for processing.

Day #89

No comments:

Post a Comment