HTML5 Game Development Basics
Are HTML5 games the future? Who knows, but I do know they are popular, easy to make, and overall fun to make. Below I am going to walk you through creating your first game in HTML5 and JavaScript. This walk-through will mostly be showing you how to do specific things in HTML5 to build games, not a copy and paste to make your own game. You will have to use what you learn from this and implement it yourself.
Creating the HTML Page and Canvas
To first get started, we have to create the canvas we will be drawing and animating to. Not all browsers support canvas and canvas functions so you will have to do support checking. Let us create a simple HTML page in our project folder.
<!doctype html>
<html>
<head>
<title>HTML5 Game Test</title>
<script src="gamefunctions.js"></script>
</head>
<body>
<canvas id="canvas" width="500" height="500" style="border:1px solid black" tabindex="1">
Your browser doesn't support canvas.
</canvas>
</body>
</html>
As you can see we have the canvas element and assigned an ID to it so our JavaScript file “gamefunctions.js” can easily identify it.
Canvas’ by default don’t focus on click, so we have to create a work around for this. There are many ways to do this but the way I normally do it is by event listeners that then focus.
window.onload = function() {
initGame();
}
var g_Canvas = null;
var g_Context = null;
var g_Keys = [];
function initGame() {
g_Canvas = document.getElementById('canvas');
g_Context = g_Canvas.getContext('2d');
g_Canvas.addEventListener('mousedown',canvasFocus,false);
g_Canvas.addEventListener('keydown',canvasKeyDown,false);
g_Canvas.addEventListener('keyup',canvasKeyUp,false);
gameLoop();
}
function canvasFocus(e) {
if(e.type == 'mousedown') {
g_Canvas.focus();
return false;
}
return true;
}
function gameLoop() {
}
function canvasKeyDown(e) {
if(g_Keys.indexOf(e.keyCode) == -1)
g_Keys.push(e.keyCode);
return false;
}
function canvasKeyUp(e) {
delete_array(e.keyCode,g_Keys);
return false;
}
function delete_array(needle, haystack) {
var i = 0;
var size = haystack.length
for(i; i < size; ++i) {
if(haystack[i] == needle) {
haystack.splice(i,1);
return haystack;
}
}
return haystack;
}
We create 2 global variables for the canvas and the canvas’ context. We then assign a mouse down event listener that will focus to the canvas. To add to this, we also created a call to gameLoop() so the main loop for the game will get started when the game initiates. One last thing we did was create two events for the keyboard. This is used to track the keyboard keys that are pressed. With games you often have multiple keys pressed at once, so this allows us to have combos and multiple functions going on at the same time.
Right now we are just setting up the most basic of functions we will use in the future. These functions will most likely be in every game you create for HTML5 unless changes are made to it in the future or if you use a library.
Drawing the Character
With our game we need to draw our character. This can be as simple or advance as you want. Also we must be sure the character drawing function accepts X and Y coordinates for 2D games and an extra 3rd Z variable for 3D games. I also add other variables such as speed and direction for smoother starts and changing of directions, but that will be found under “Controlling the Character”. We are going to draw a simple 2D player using the variable in a global player variable that contains its location and other information. But for drawing the player we only need its location.
var g_Player = {x:250,y:250,speed:0,speedMax:5,speedIncrement:1};
function gameLoop() {
drawPlayer();
setTimeout(gameLoop,(1000/30)); // Execute Game Loop at 30FPS
}
function drawPlayer() {
g_Context.beginPath();
g_Context.strokeStyle = "#ff00d2";
g_Context.lineWidth = 1;
g_Context.moveTo(g_Player.x,g_Player.y-6); // Top Point
g_Context.lineTo(g_Player.x+6,g_Player.y+6); // Bottom Right Point
g_Context.lineTo(g_Player.x-6,g_Player.y+6); // Bottom Left Point
g_Context.lineTo(g_Player.x,g_Player.y-6); // Top Point
g_Context.stroke();
g_Context.closePath();
}
We drew a simple triangle player centered on the g_Player X and Y value. You can get creative with this part or just load an image. I have this setup so the player doesn’t rotate. If you want the player to rotate you will need to work with another variable such as angle and work with that.
Handling Player Input and Controlling the Character
Player input is nearly done already from our first step, but we don’t know how to handle it yet. We add onto an existing function gameLoop to add control actions. You could alternatively add all of these to a new function and call it from gameLoop but this command does need to be ran whenever gameLoop is.
function gameLoop() {
/*
37: Left Arrow
38: Up Arrow
39: Right Arrow
40: Down Arrow
19: Pause / Break
32: Space
*/
if(g_Keys.indexOf(37) != -1) {
g_Player.x -= 1; // Move Left 1
}
if(g_Keys.indexOf(39) != -1) {
g_Player.x += 1; // Move Right 1
}
if(g_Keys.indexOf(19) != -1) {
// Pause Game
}
if(g_Keys.indexOf(32) != -1) {
fireBullet(g_Player.x,g_Player.y);
}
}
We check the active keys in g_Keys by using indexOf and the keycode. If the key exists in the array we handle that key how it would act. I also commented out some keycodes that are commonly used such as arrow keys, space and pause. With the way we handle keys you can also check if multiple keys are pressed which help with more advance games or character movements.
Drawing, Tracking and Deleting Objects
If your game only has one object (the player) you are going to be fairly bored. To solve this we have to create many objects, and track them. This isn’t very difficult, but it does require a good way to track many items like bullets, enemies, walls, boxes, items and anything else you may have. Below is a way I tracked bullets and then moved them every time gameLoop() was reached.
var g_Bullets = [];
function fireBullet(x,y) {
g_Context.beginPath();
g_Context.arc(x,y,3,0,2*Math.PI,false);
g_Context.fillStyle = '#0000ff';
g_Context.fill();
g_Context.closePath();
g_Bullets.push({x:x,y:y});
}
function moveBullets() {
var i = 0;
var remove = [];
g_Context.beginPath();
g_Context.fillStyle = '#0000ff';
for(i; i < g_Bullets.length; ++i) {
// Delete Bullet
g_Context.clearRect(g_Bullets[i].x-4,g_Bullets[i].y-4,8,8);
if(g_Bullets[i].y > 0) { // Check if Bullet is still in screen
g_Bullets[i].y -= 2; // Move Bullet Up 2
g_Context.beginPath();
g_Context.arc(g_Bullets[i].x,g_Bullets[i].y,3,0,2*Math.PI,false);
g_Context.fill();
}else{
// Add to be Remove from Array so not to be handled again
remove.push(i);
}
}
g_Context.closePath();
// Clean up removed items
for(i = 0; i < remove.length; ++i) {
delete_array(g_Bullets[remove[i]],g_Bullets);
}
}
function gameLoop() {
moveBullets();
}
Above we added moveBullets to the gameLoop so all the entities that need to be moved will be. In moveBullets() we loop through all bullets that are alive (existing), and clear / erase them. If the bullet is still in play (visible / no collision) we move them to the next location and draw. If the bullet is no longer in play we add it to a remove array that we then loop through to delete all items we no longer need. This is important to make your game not track items that are no longer needed.
Collision Detection
Collision detection is another important part of game play. You want to know if a bullet hit an enemy, the player hits a wall, or an enemy hits a wall. The way to do this is fairly simple if you keep track of all items properly. But to show you how to do this is more difficult without creating enemies to do detection with. Because of this we are going to just do collision detection with the player and the left and right walls. You can apply this to the bullets and enemies in the future.
function drawPlayer() {
if((g_Player.x+6) > 500 || (g_Player.x-3 < 6) {
return;
}
/* Rest of drawPlayer() Code previously shown */
}
We simply check if the player edges are touching the borders based on X and Y values. You will do this will bullets. After the bullets move you create a function checking all the bullets (or add this into the moveBullets function) and if the bullet is in the X and Y and X+Width and Y+Height of the enemy you have the enemy delete and the bullet delete. Of course having sound or an animation will make the effect much better than just despawning entities.
Sound and Volume
The last part we are going to look into is sound and volume. Having sound in your game adds that extra bit to it. Be sure that if you do have sound you have volume controls. I don’t know how many times I saw an HTML5 audio object that didn’t have volume control and it forced me to leave the site because it was too loud.
function playSound(filename,duration) {
var a = document.createElement('audio');
a.src = filename;
document.body.appendChild(a);
a.volume = 0.3;
a.play();
setTimeout(function() {
document.body.removeChild(a);
},duration);
}
We can now call playSound() with the filename (including extension) and the duration we want the sound to play. The reason for the duration is so the audio file gets removed from the DOM when finished. There are other alternative ways to detect when the sound file is finished playing but I just needed a quick and dirty way to get it to work.
Hopefully the information above will help you create some HTML5 games. I am really happy that nearly anyone can create a game now, and have it be visible and public easily. In the next few years I believe HTML5 games will become really large and have a lot of interesting game sites. Since it is so easy to integrate with AJAX and other websites we can expect a lot of new interesting ideas soon.