Build a vertical scrolling shooter game with HTML5 canvas – Part 2

February 13th, 2011

Last time we built the basic structure of our game, but moving a block around while some others move down the screen doesn’t really make a great game. So let’s change the blocks to actual space ship graphics and give our ship the ability to shoot lasers.

Changing the blocks to ship graphics isn’t that hard. We just need to change the method we use to draw the ship and enemies from fillRect to drawImage. Here’s the two images I’m using:

Now we just need to make some adjustments to the JavaScript. The first thing we do is load the images, so add these two variables:

1
var enemy, ship;

And then change the init function to this:

1
2
3
4
5
6
7
8
9
10
11
function init() {
  canvas = document.getElementById('canvas');
  ctx = canvas.getContext('2d');
  enemy = new Image();
  enemy.src = '8bit_enemy.png';
  ship = new Image();
  ship.src = 'ship.png';
  setInterval(gameLoop, 25);
  document.addEventListener('keydown', keyDown, false);
  document.addEventListener('keyup', keyUp, false);
}

We’ve add four lines that first tell the variables ship and enemy that they’re images and then we set the source of each image. Now that we’ve loaded the images, we need to actually draw them on the canvas. In the drawShip function, we need to change this:

1
2
ctx.fillStyle = '#0f0';
ctx.fillRect(ship_x, ship_y, ship_w, ship_h);

to this:

1
ctx.drawImage(ship, ship_x, ship_y);

Now if you test the game, you’ll see the green block has been replaced with the ship graphic. Now on to the enemy ships. It’s the exact same thing, in the drawEnemies function, change this:

1
2
ctx.fillStyle = '#f00';
ctx.fillRect(enemies[i][0], enemies[i][1], enemy_w, enemy_h);

to this:

1
ctx.drawImage(enemy, enemies[i][0], enemies[i][1]);

Now, the enemies will appear on the canvas as the enemy ship png I created. Now let’s make our ship shoot something. First we need to add a couple of variables:

1
var laserTotal = 2, lasers = [];

We want to put a limit on the amount of lasers that a player can have on the screen at once, just to make things a bit more challenging, so laserTotal is set to 2, which actually means 3 lasers because arrays start at 0. Next, we need to add this line to the keyDown function:

1
if (e.keyCode == 88 && lasers.length <= laserTotal) lasers.push([ship_x + 25, ship_y - 20, 4, 20]);

This says, if the x key is pressed and then number of lasers in the laser array is less then totalLaser, then add a laser to our laser array. We’re positioning the laser to be at the front of the current position of our ship. The next step is to draw the laser on the stage. We need to create a function called drawLaser.

1
2
3
4
5
6
7
function drawLaser() {
  if (lasers.length)
    for (var i = 0; i < lasers.length; i++) {
      ctx.fillStyle = '#f00';
      ctx.fillRect(lasers[i][0],lasers[i][1],lasers[i][2],lasers[i][3])
    }
}

It’s pretty much the same thing as how drawEnemies function, except we’re checking to see if there are any lasers in the array first because if the player hasn’t shot one yet, we don’t want to draw any. The lasers aren’t going to do any good unless we make them move, so now we’ll add the moveLaser function:

1
2
3
4
5
6
7
8
9
function moveLaser() {
  for (var i = 0; i < lasers.length; i++) {
    if (lasers[i][1] > -11) {
      lasers[i][1] -= 10;
    } else if (lasers[i][1] < -10) {
      lasers.splice(i, 1);
    }
  }
}

With moveLaser, we’re running a loop and if the laser is visible in the canvas, we move it up 10 pixels, otherwise, if it’s passed beyond the top, we remove it from the array. The last thing we have to do is up date the gameLoop function:

1
2
3
4
5
6
7
8
function gameLoop() {
  clearCanvas();
  moveEnemies();
  moveLaser();
  drawEnemies();
  drawShip();
  drawLaser();
}

And all these changes should get us this. Next time, we’ll have the lasers actually hit something! Here’s the complete code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>HTML5 Canvas Shooter Game Tutorial Part 1</title>
<style>
body {
  padding:0;
  margin:0;
  background:#666;
}
canvas {
  display:block;
  margin:30px auto 0;
  border:1px dashed #ccc;
  background:#000;
}
</style>
<script>
var canvas,
    ctx,
    width = 600,
    height = 600,
    enemy,
    enemyTotal = 5,
    enemies = [],
    enemy_x = 50,
    enemy_y = -45,
    enemy_w = 50,
    enemy_h = 50,
    speed = 3,
    rightKey = false,
    leftKey = false,
    upKey = false,
    downKey = false,
    ship,
    ship_x = (width / 2) - 25, ship_y = height - 75, ship_w = 50, ship_h = 50,
                laserTotal = 2,
    lasers = [];

for (var i = 0; i < enemyTotal; i++) {
 enemies.push([enemy_x, enemy_y, enemy_w, enemy_h, speed]);
 enemy_x += enemy_w + 60;
}

function clearCanvas() {
 ctx.clearRect(0,0,width,height);
}

function drawEnemies() {
 for (var i = 0; i < enemies.length; i++) {
                ctx.drawImage(enemy, enemies[i][0], enemies[i][1]);
 }
}

function drawShip() {
 if (rightKey) ship_x += 5;
 else if (leftKey) ship_x -= 5;
 if (upKey) ship_y -= 5;
 else if (downKey) ship_y += 5;
 if (ship_x <= 0) ship_x = 0;
 if ((ship_x + ship_w) >= width) ship_x = width - ship_w;
  if (ship_y <= 0) ship_y = 0;
 if ((ship_y + ship_h) >= height) ship_y = height - ship_h;
        ctx.drawImage(ship, ship_x, ship_y);
}

function moveEnemies() {
  for (var i = 0; i < enemies.length; i++) {
   if (enemies[i][1] < height) {
     enemies[i][1] += enemies[i][4];
   } else if (enemies[i][1] > height - 1) {
      enemies[i][1] = -45;
    }
  }
}
function drawLaser() {
  if (lasers.length)
    for (var i = 0; i < lasers.length; i++) {
     ctx.fillStyle = '#f00';
     ctx.fillRect(lasers[i][0],lasers[i][1],lasers[i][2],lasers[i][3])
   }
}
function moveLaser() {
 for (var i = 0; i < lasers.length; i++) {
   if (lasers[i][1] > -11) {
      lasers[i][1] -= 10;
    } else if (lasers[i][1] < -10) {
     lasers.splice(i, 1);
   }
 }
}

function init() {
 canvas = document.getElementById('canvas');
 ctx = canvas.getContext('2d');
 enemy = new Image();
 enemy.src = '8bit_enemy.png';
 ship = new Image();
 ship.src = 'ship.png';
 setInterval(gameLoop, 25);
 document.addEventListener('keydown', keyDown, false);
 document.addEventListener('keyup', keyUp, false);
}
function gameLoop() {
 clearCanvas();
 moveEnemies();
 moveLaser();
 drawEnemies();
 drawShip();
 drawLaser();
}

function keyDown(e) {
 if (e.keyCode == 39) rightKey = true;
 else if (e.keyCode == 37) leftKey = true;
 if (e.keyCode == 38) upKey = true;
 else if (e.keyCode == 40) downKey = true;
 if (e.keyCode == 88 && lasers.length <= laserTotal) lasers.push([ship_x + 25, ship_y - 20, 4, 20]);

}

function keyUp(e) {
 if (e.keyCode == 39) rightKey = false;
 else if (e.keyCode == 37) leftKey = false;
 if (e.keyCode == 38) upKey = false;
 else if (e.keyCode == 40) downKey = false;
}

window.onload = init;
</script>
</head>

<body>
  <canvas id="canvas" width="600" height="600"></canvas>
</body>
</html>

Leave a Reply

Your email address will not be published. Required fields are marked *