Tutorial: Simple game with HTML5 Canvas
Part 1 - Introduction & Background
Part 2 - Character & Animation
Part 3 - Physics & Controls
Part 4 - Platforms & Collisions
Part 5 - Scrolling & Game States
If you are interested in news and updates of that tutorial just follow me on twitter: [MichalBe's Twitter]
Because 10KApart is closed now, and we are all waiting for the results, it is good time to remind my very simple "Stairs to heaven" game and explain in details how it was made.
INTRODUCTION
StH is very simple clone of Doodle Jump, but to be honest I was inspired by Icy Tower and discover DJ after I submit StH to the competition. Never mind.The goal is to control little angel & jump on the two kinds of platforms - orange (regular ones) and green (super high jump springboards). The game ends when the angel falls down to the bottom of the screen. Try it: [Stairs to heaven].
I create that game in about 8hours and later, after playing more and more, I discover few bugs so in this tutorial I want to fix it all. Let's do it!
Part 1. BACKGROUND
Because whole game, including images and scripts, couldn't be over 10K, I didn't want to use image on the background. It was cheaper to draw some generic-like stuff using canvas drawing functions.
First of all we need little HTML, nothing special, just one canvas element with some unique id, little bit of CSS and include of not existing yet game.js:
<html>
<head>
<title>Simple game with HTML5 Canvas</title>
<style>
body {
margin:0px;
padding:0px;
text-align:center;
}
canvas{
outline:0;
border:1px solid #000;
margin-left: auto;
margin-right: auto;
}
</style>
</head>
<body>
<canvas id='c'></canvas>
<script src="game.js"></script>
</body>
</html>That's all in HTML we will need during this tutorial.Ok, so let's create some Javascript.
First of all we need to create few global (for now, I know that global = evil) variables & change canvas attributes. That will be enough:
var width = 320,
//width of the canvas
height = 500,
//height of the canvas
c = document.getElementById('c'),
//canvas itself
ctx = c.getContext('2d');
//and two-dimensional graphic context of the
//canvas, the only one supported by all
//browsers for now
c.width = width;
c.height = height;
//setting canvas size First of all its important to understand one thing about canvas - it is not possible to move objects in the canvas surface. It's necessarily to clear it, whole or in the parts, on each frame. To achieve this, let's create clear() function. var clear = function(){
ctx.fillStyle = '#d0e7f9';
//set active color to #d0e... (nice blue)
//UPDATE - as 'Ped7g' noticed - using clearRect() in here is useless, we cover whole surface of the canvas with blue rectangle two lines below. I just forget to remove that line
//ctx.clearRect(0, 0, width, height);
//clear whole surface
ctx.beginPath();
//start drawing
ctx.rect(0, 0, width, height);
//draw rectangle from point (0, 0) to
//(width, height) covering whole canvas
ctx.closePath();
//end drawing
ctx.fill();
//fill rectangle with active
//color selected before
}One colored clear background is boring as hell, so let's draw some clouds on it. Maybe not regular clouds, but simple, semitransparent circles imitating clouds. First we will draw some in random places of the canvas, each with different size and transparency. We will keep all the informations about circles in 2d array (there are no two-dimensional arrays in JS, best way to solve this is just put one Array into another). var howManyCircles = 10, circles = [];
for (var i = 0; i < howManyCircles; i++)
circles.push([Math.random() * width, Math.random() * height, Math.random() * 100, Math.random() / 2]);
//add information about circles into
//the 'circles' Array. It is x & y positions,
//radius from 0-100 and transparency
//from 0-0.5 (0 is invisible, 1 no transparency)
var DrawCircles = function(){
for (var i = 0; i < howManyCircles; i++) {
ctx.fillStyle = 'rgba(255, 255, 255, ' + circles[i][3] + ')';
//white color with transparency in rgba
ctx.beginPath();
ctx.arc(circles[i][0], circles[i][1], circles[i][2], 0, Math.PI * 2, true);
//arc(x, y, radius, startAngle, endAngle, anticlockwise)
//circle has always PI*2 end angle
ctx.closePath();
ctx.fill();
}
};
Nice, but boring less only a little. Why are the clouds standing still? Lets make a tiny little function with one Number type argument, which moves clouds down given number of pixels, and when particular circle disappears under the canvas, it will moves it on the top with changed position X, radius and transparency:var MoveCircles = function(deltaY){
for (var i = 0; i < howManyCircles; i++) {
if (circles[i][1] - circles[i][2] > height) {
//the circle is under the screen so we change
//informations about it
circles[i][0] = Math.random() * width;
circles[i][2] = Math.random() * 100;
circles[i][1] = 0 - circles[i][2];
circles[i][3] = Math.random() / 2;
} else {
//move circle deltaY pixels down
circles[i][1] += deltaY;
}
}
};Now, last but not least, let's create main game loop and connect everything we create for now in there. Each frame will clear the screen, move circles 5px lower, draw them and after 1/50sec call another frame. I use two setTimeouts except one setInterval, but I'm not pretty sure why:). I know that there was some performance issues in IE back in the days or something.
Also don't forget to add gLoop variable to that declared at the beginning.var width = 320,
//width of the canvas
height = 500,
//height of the canvas
gLoop,
(...) //rest of the code goes here
var GameLoop = function(){
clear();
MoveCircles(5);
DrawCircles();
gLoop = setTimeout(GameLoop, 1000 / 50);
}
GameLoop();According to Luis Giribone's comment below, I avoid Intervals and use Timeouts instead intentionally - Interval is called every 1000/fps seconds - even if the previous one disn't not finished yet. If you use Timeout, it will call another one only after previous was finished. I hope it is clear now.
I also want to thanks Ped7g, author of Whiskas & Pedigree Javascript ad game for catching mistakes.
Final result of that part should looks like this: [Simple game with HTML5 Canvas part 1], and sources are available on my Github account: [MichalBe]
Tutorial: Simple game with HTML5 Canvas
Part 1 - Introduction & Background
Part 2 - Character & Animation
Part 3 - Physics & Controls
Part 4 - Platforms & Collisions
Part 5 - Scrolling & Game States


You are the man! Thanks for posting this great series!
ReplyDeleteExcellent tutorial! I am doing game-coding tutorials for some 10 years by now, and it's one of the most thorough, and well written! Many Thanks!
ReplyDeleteP.S. Post Part 5 (The Scroll) - I beg You!
Great article, thanks for posting this! I've definitely learned quite a bit, and I plan to follow along.
ReplyDeleteThanks again!
This is just great, really like how you broke it down. I'll be having a go myself for sure!
ReplyDeletewhy do you do "ctx.clearRect(0, 0, width, height);" to clear whole surface, when you fill up whole by blue just after that (i.e. clearing it twice effectively)
ReplyDeleteDoes it solve some browser quirk? (tried to patch it here for ff3.6, works OK without the clearRect)
ck ck ck...
ReplyDeletecan be used as background ... awesome
thanks for tutor^^
salam from si bloglang anu ganteng kalem tea
congrats! keep up the good work/this is a great presentation.
ReplyDeletecanvas Print
Awesome tuts! Thanks for posting.
ReplyDeleteJust wondering, is there any specific reasoning behind you placing your functions within variables?
I find it easier just to write them as functions, but I'm n00by so I don't know if there's logic behind it.
Thanks, nice to hear someone likes it:). You can find useful information about declaring functions for example in here: http://zazaq.com/2010/08/07/javascript-function-declaration-vs-function-expression/
ReplyDeletei made only a simple change to avoid setTimeouts
ReplyDelete// game init obj
var GameLoop = function(){
clear();
moveCircles(5);
drawCircles();
}
//end of code init the game
gLoop = setInterval( GameLoop, 1000/fps );
so i don't set a timeout every GameLoop
and is the same code to clear the interval.
Thanks for the tutorial, great game!
Avoiding Intervals and using Timeouts instead was my point in here - Interval is called every 1000/fps seconds - even if the previous one did not finished yet. If you use Timeout, it will call another one only after previous was finished.
ReplyDeletewow, hard to see that point,
ReplyDeletethanks for the clarification :)
you're welcome, that are tutorials for:)
ReplyDeleteIt doesn't do anything. I copy and pasted it and it didn't work. it just shows a blank box that is the wrong size in my chrome tab.
ReplyDeleteSo you are doing something in the wrong way. Try the code from repo.
ReplyDeleteHow can I make the circles move on the x axis instead? :)
ReplyDeleteThanks. I got it working now. Now I'm just trying to understand some of the code that I wrote here and why it works the way it does.
ReplyDeleteOn the circles.push([]) why does it have the [] inside the () of the push?
ReplyDeleteHow do we make the clouds go different speeds between like 1 and 10?
ReplyDeleteprovide different deltaY
ReplyDeleteI mean how do you make each cloud have it's own individual speed? Like one like would go 5px the other would go 10px for example.
ReplyDeletethe answer is still the same - each cloud should have its own deltaY
ReplyDeleteI see. This code thing is sooooo logical.
ReplyDeleteExcellent tutorial! Everything works and it's perfect for a beginner with Canvas/JS.
ReplyDeleteOne question - is there any reason you put comments under your statements? It was just slightly difficult to read for me, that's all.
It's a useful tutorial!!!
ReplyDeleteBut just want to ask what is the usage for the game.js?You didn't mention it.
You have to put all the javaScript code inside this file.
ReplyDeleteOh I see, thanks!!
ReplyDeleteBut I just see the source code in your example, all the javaScript code put in the HTML file but not the game.js?
Check github:
ReplyDeletehttps://github.com/michalbe/Simple-game-with-HTML5-Canvas
everything is in .js file.
Thanx man. First for your great tutorial, second for jsbin :).
ReplyDeleteim pretty sure i did everything right, but i only get a blue screen and no clouds. Any suggestions?
ReplyDeleteSame here. I dont see any cloud either.
Deletefixed it
ReplyDeleteWhy do you make functions using var and not
ReplyDeletefunction funcname()?
Thanks for this great introduction to game development using HTML5 canvas, I managed to create this game after reading your post ! :)
ReplyDeletehttp://ole.im/tetris
Great tutorials thanks html 5 games coding so simple than flash games
ReplyDeleteThanks for your tutorial. I learned lots from here like a e-book. Keep up your work.
ReplyDeleteWonderful training cheers html page Five video games code consequently straightforward as compared to thumb games.
ReplyDeleteThanks for sharing your info. I really appreciate your efforts and I will be waiting for your further write ups thanks once again.
ReplyDeleteThanks for the great tutorial. I really think that HTML5 will prove to be the future of online games and am excited to see what all the developers there will do with the technology.
ReplyDelete