Initialise a canvas
<canvas id="c" width="640" height="480"></canvas>
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
Note:
- Width and height determine the canvas size.
- CSS width and height will stretch the canvas.
2d
refers to the rendering context (API). Other options includewebgl
.
Basic drawing with Canvas
There are several ways of drawing on the 2d drawing context.
- Rects (rectangles)
- Paths
- Text
- Images
Drawing Rectangles
Rectangles can fill, stroke, or clear an area.
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
// Black rectangle
ctx.fillRect(0,0,200,200);
// Black outline
ctx.strokeRect(200,0,200,200);
// White rectangle (cleared area)
ctx.clearRect(50,50,100,100);
See the Pen Canvas Rectangles by Ashley Kyd (@AshKyd) on CodePen.
Drawing Paths
A bit like Logo without the turtle graphic.
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
// Draw a triangle
ctx.beginPath();
ctx.moveTo(0,100);
ctx.lineTo(50,0);
ctx.lineTo(100,100);
ctx.closePath();
ctx.stroke();
// Draw a circle
ctx.beginPath();
ctx.arc(200,50,50,0,Math.PI*2);
ctx.fill();
See the Pen Canvas Paths by Ashley Kyd (@AshKyd) on CodePen.
Path Methods
You can use these methods to draw and fill lines onscreen.
Drawing Text
- The most basic use is
ctx.fillText(text, x, y, [maxWidth])
- Use
textAlign=center
andtextBaseline=middle
to center on the specified point.
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
// Default text
ctx.strokeRect(0,0,100,100);
ctx.fillText('#brisjs',50,50);
// Centered Text
ctx.strokeRect(100,0,100,100);
ctx.font = '12px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle'
ctx.fillText('#brisjs',150,50);
See the Pen Canvas Text by Ashley Kyd (@AshKyd) on CodePen.
Drawing Images
Use drawImage(img, x, y)
to splat any image or canvas element down into your current context.
var canvas = document.getElementById('c'); var ctx = canvas.getContext('2d');
// load an image and draw it in! var img = document.createElement('img'); img.onload = function(){ // Draw the image ctx.drawImage(img,0,0);
// and some text ctx.font = 'bold 40px Impact'; ctx.textAlign = 'center'; ctx.strokeStyle = '#fff'; ctx.lineWidth = 2; ctx.fillText('MEMES AT #brisjs',200,40); ctx.strokeText('MEMES AT #brisjs',200,40);
}
img.src = 'http://lorempixel.com/400/400/animals/';See the Pen Canvas Images by Ashley Kyd (@AshKyd) on CodePen.
Using Transforms
Transforms adjust the coordinate system your drawing tools use.
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
// Example translate
ctx.strokeStyle = 'darkgreen';
ctx.strokeRect(0,0,100,100);
ctx.strokeStyle = 'limegreen';
ctx.translate(100,100);
ctx.strokeRect(0,0,100,100);
ctx.strokeStyle = 'black';
ctx.rotate(Math.PI/4);
ctx.strokeRect(0,0,100,100);
// Make some isometric tiles with setTransform
// ash.ms/blog/2012-07-08/isometric-tile-transforms
ctx.strokeStyle = 'purple';
ctx.setTransform(1,-.5,1,.5,0,0);
ctx.strokeRect(0,200,100,100);
ctx.strokeRect(100,200,100,100);
ctx.strokeRect(0,300,100,100);
ctx.strokeRect(100,300,100,100);
See the Pen Canvas Transforms by Ashley Kyd (@AshKyd) on CodePen.
- Transforms are useful for when you have a self-contained item and want it to be able to move.
- For more information, I've previously written on transforms for isometric games.
Animation
setInterval is so 1995. Use the requestAnimationFrame
method to call back before the next screen repaint.
var gameLoop = function(){
// Do stuff
requestAnimationFrame(gameLoop);
}
requestAnimationFrame(gameLoop);
requestAnimationFrame
won't fire if the browser isn't painting, for instance in another tab or minimised.- Unit movement should be calculable as a vector, otherwise everything will stop or slow down with the render process.
Let's get moving
This demo shows the basics of animation. The sine wave is calculable based on the current time.
var canvas = document.getElementById('c'); var ctx = canvas.getContext('2d');
function sineWave(){ var yPos = Math.sin(Date.now() / 500 ) 100; ctx.fillRect(0, yPos, 10, 10); }
var gameLoop = function(){ ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.save(); ctx.translate(150, 150);
// Let's draw some sine waves for(var i=0; i<10; i++){ ctx.save(); // pi</em>2 radians == 360° ctx.rotate((i/10)<em>Math.<span class="caps">PI</span></em>2); sineWave(); ctx.restore(); } ctx.restore(); requestAnimationFrame(gameLoop);
}
requestAnimationFrame(gameLoop);See the Pen Canvas Animation by Ashley Kyd (@AshKyd) on CodePen.
Particles
Particles are one of the most useful things you can have in a 2D game.
See the Pen Canvas Particle Generator by Ashley Kyd (@AshKyd) on CodePen.
- Particles can be anything you want, but gradients are slow to draw so you'll need to cache them.
- You can plug in one of many physics engines from NPM, but it's easier to accelerate out from a center point.
Polar Defender (my entry into the 2014 #js13k)
js13k is a month-long game competition to make a game in under 13 kb.
- Polar coordinates &
.rotate()
make it east to do a radial game. - SVG sprites: scalable, re-colourable assets.
- "Everything's a particle" approach simplifies collision detection.
- jsfxr for 8-bit sounds.
- Using a bunch of Unicode emoji as game assets (gotta save space).
- Code on GitHub
Where to go from here
There's a bunch of stuff already out there to make your life easier. Here's some of my favourites:
- Pick a game engine (or do it by hand)
- NPM is a treasure trove of amazing things
- freenode/#bbg – browser based games
- Learn about Juice in a talk by Martin Jonasson and Petri Purho