Create a Simple Space Shooter Game in HTML5 With EaselJS
Last year, I showed you how to create a shoot-'em-up game with Flash and AS3. With HTML5's rise in popularity (and capabilities), let's take a look at how to do the same with HTML5, JavaScript, and EaselJS.
Final Result Preview
Let's take a look at the final result we will be working towards:
Step 1: Brief Overview
Using pre-made sprites we will code an entertaining Space Shooter game in HTML5 using the EaselJS library.
The player will be able to control a spaceship and shoot multiple enemies while traveling in space.
Step 2: Interface
A simple and futuristic interface will be used, this involves bitmaps and more. I've used a great sprite library in the demo of this tutorial, these are part of the free Sinistar Clone Graphics.
The interface resources required for this tutorial can be found in the attached download.
Step 3: Get EaselJS
The EaselJS library will be used to build our game, make sure you read the Getting Started tutorial if you're new to this library.
You can download EaselJS from its official website.
Step 4: HTML Structure
Let's prepare our HTML document, it is a simple HTML structure to begin writing our app. Save this as Shooter.html
.
1 |
|
2 |
<!DOCTYPE html>
|
3 |
<html>
|
4 |
<head>
|
5 |
<title>Shooter</title> |
6 |
</head>
|
7 |
<body>
|
8 |
</body>
|
9 |
</html>
|
Step 5: Hide Mobile Hightlight
Let's add a little bit of CSS too, this line will remove the default highlight when you tap on an element using a mobile browser; without this, the mobile experience would decrease drastically.
1 |
|
2 |
<!DOCTYPE html>
|
3 |
<html>
|
4 |
<head>
|
5 |
<title>Shooter</title> |
6 |
|
7 |
<style>*{-webkit-tap-highlight-color: rgba(0, 0, 0, 0);}</style> |
8 |
|
9 |
</head>
|
10 |
<body>
|
11 |
</body>
|
12 |
</html>
|
Step 6: JavaScript Libraries
The following code adds the necessary JavaScript libraries required for our app to work.
1 |
|
2 |
<!DOCTYPE html>
|
3 |
<html>
|
4 |
<head>
|
5 |
<title>Shooter</title> |
6 |
|
7 |
<style>*{-webkit-tap-highlight-color: rgba(0, 0, 0, 0);}</style> |
8 |
|
9 |
<script src="easel.js"></script> |
10 |
<script src="Tween.js"></script> |
11 |
<script src="sound.js"></script> |
12 |
<script src="Main.js"></script> |
13 |
</head>
|
14 |
<body>
|
15 |
</body>
|
16 |
</html>
|
Main.js
is the file we will use to store all our own functions for the game. Create it now and save it in the same folder as Shooter.html
. You'll also need to download the EaselJS libraries listed.
Step 7: Call Main Function
In the next lines we call our main function; this is the function that will start our application, it'll be created later in our JavaScript code.
1 |
|
2 |
<!DOCTYPE html>
|
3 |
<html>
|
4 |
<head>
|
5 |
<title>Shooter</title> |
6 |
|
7 |
<style>*{-webkit-tap-highlight-color: rgba(0, 0, 0, 0);}</style> |
8 |
|
9 |
<script src="easel.js"></script> |
10 |
<script src="Tween.js"></script> |
11 |
<script src="sound.js"></script> |
12 |
<script src="Main.js"></script> |
13 |
|
14 |
</head>
|
15 |
<body onload="Main();"> |
16 |
</body>
|
17 |
</html>
|
Step 8: Canvas Element
The Canvas is added in this line. We assign an ID to reference it later and also set its width and height.
1 |
|
2 |
<!DOCTYPE html>
|
3 |
<html>
|
4 |
<head>
|
5 |
<title>Shooter</title> |
6 |
|
7 |
<style>*{-webkit-tap-highlight-color: rgba(0, 0, 0, 0);}</style> |
8 |
|
9 |
<script src="easel.js"></script> |
10 |
<script src="Tween.js"></script> |
11 |
<script src="sound.js"></script> |
12 |
<script src="Main.js"></script> |
13 |
|
14 |
</head>
|
15 |
<body onload="Main();"> |
16 |
<canvas id="Shooter" width="320" height="480"></canvas> |
17 |
</body>
|
18 |
</html>
|
Step 9: Starting the JavaScript
Let's begin our game creation!
Open your preferred JavaScript editor (any text editor will work, but you won't have syntax highlighting) and prepare to write your awesome game. Open the Main.js
file you created earlier.
Step 10: Define Canvas
We'll start by defining all the graphic and logic variables.
The next variables represent the HTML canvas element and the stage that will be linked to it. (The stage variable will behave in a similar way to the stage in an AS3 Flash project.)
1 |
|
2 |
/* Define Canvas */
|
3 |
|
4 |
var canvas; |
5 |
var stage; |
Step 11: Background
The next variables store the background images. Two tiled images are used to create an infinitely scrolling background.
1 |
|
2 |
/* Background */
|
3 |
|
4 |
var bgImg = new Image(); |
5 |
var bg; |
6 |
var bg2Img = new Image(); |
7 |
var bg2; |
Step 12: Ship
This is the Ship that will be used as the player character or hero.
1 |
|
2 |
/* Ship */
|
3 |
|
4 |
var sImg = new Image(); |
5 |
var ship; |
Step 13: Enemy
Multiple enemies will be on the stage; they will use this as the source graphic.
1 |
|
2 |
/* Enemy */
|
3 |
|
4 |
var eImg = new Image(); |
Step 14: Boss
A boss will be present in the game, bigger and with more health than the other enemies. These variables are used to instantiate it.
1 |
|
2 |
/* Boss */
|
3 |
|
4 |
var bImg = new Image(); |
5 |
var boss; |
Step 15: Lives
The "life" icon. Three lives are given at the start, and you lose one when hit by an enemy.
1 |
|
2 |
/* Lives */
|
3 |
|
4 |
var lImg = new Image(); |
Step 16: Bullets
This is your weapon: fire bullets at the enemies to kill them. This variable stores the source image.
1 |
|
2 |
/* Bullets */
|
3 |
|
4 |
var bltImg = new Image(); |
Step 17: Alert Graphics
Two alerts are used in the game, one for when you win and one for when you lose. We'll see how to determine a win or a loss later in this tutorial.
1 |
|
2 |
/* Alert */
|
3 |
|
4 |
var winImg = new Image(); |
5 |
var loseImg = new Image(); |
6 |
var win; |
7 |
var lose; |
Step 16: Variables
These are the variables we'll use, read the comments in the code to know more about them. Some of their names are self-explanatory and so have no comments.
1 |
|
2 |
var lives = new Container(); //stores the lives gfx |
3 |
var bullets = new Container(); //stores the bullets gfx |
4 |
var enemies = new Container(); //stores the enemies gfx |
5 |
var bossHealth = 20; |
6 |
var score; |
7 |
var gfxLoaded = 0; //used as a preloader, counts the already loaded items |
8 |
var centerX = 160; |
9 |
var centerY = 240; |
10 |
var tkr = new Object(); //used as a Ticker listener |
11 |
var timerSource; //references a setInterval method |
Step 17: Sounds
We'll use sound effects to enhance the feeling of the game. You can find the sounds used in this example on Soungle.com using the keywords space, explosion and laser.
Step 18: Main Function
The Main()
function will be the first to execute when the web page is loaded, because it is referred to in the onload
attribute of the HTML document (see Step 7).
It calls the necessary functions to start the game. We'll create those functions in the next steps - everything from Step 19 to Step 23 should go inside this function.
1 |
|
2 |
function Main() |
3 |
{
|
4 |
//code...
|
5 |
}
|
Step 19: Link Canvas
This code gets the HTML canvas ID and links it to the EaselJS Stage class. This will make the stage variable behave like the stage class in AS3.
1 |
|
2 |
/* Link Canvas */
|
3 |
|
4 |
canvas = document.getElementById('Shooter'); |
5 |
stage = new Stage(canvas); |
Step 20: Enable Mouse Events
Mouse Events are disabled by default in EaselJS to improve performance; as we need those in the game we add the following line.
1 |
|
2 |
stage.mouseEventsEnabled = true; |
Step 21: Load Sounds
We'll use SoundJS to add sounds to our game. SoundJS's addBatch
method uses an array of three parameters for each call:
-
name
: The instance name you want the sound to have - this will be used to play the sound later. -
src
: The URL of the sound file. -
instances
: The number of instances that can be played at the same time.
1 |
|
2 |
/* Sound */
|
3 |
|
4 |
SoundJS.addBatch([ |
5 |
{name:'boss', src:'boss.mp3', instances:1}, |
6 |
{name:'explo', src:'explo.mp3', instances:10}, |
7 |
{name:'shot', src:'shot.mp3', instances:10}]); |
Step 22: Load Graphics
This code is used to preload the graphics with the help of a function that we'll write later. It points each Image object that we created before to the source PNG file in our document folder. A name is given to detect which image is loaded, and lastly the function that handles the loaded images is called.
1 |
|
2 |
/* Load GFX */
|
3 |
|
4 |
bgImg.src = 'bg.png'; |
5 |
bgImg.name = 'bg'; |
6 |
bgImg.onload = loadGfx; |
7 |
|
8 |
bg2Img.src = 'bg2.png'; |
9 |
bg2Img.name = 'bg2'; |
10 |
bg2Img.onload = loadGfx; |
11 |
|
12 |
sImg.src = 'ship.png'; |
13 |
sImg.name = 'ship'; |
14 |
sImg.onload = loadGfx; |
15 |
|
16 |
eImg.src = 'enemy1.png'; |
17 |
eImg.name = 'enemy'; |
18 |
eImg.onload = loadGfx; |
19 |
|
20 |
bImg.src = 'boss.png'; |
21 |
bImg.name = 'boss'; |
22 |
bImg.onload = loadGfx; |
23 |
|
24 |
lImg.src = 'live.png'; |
25 |
lImg.name = 'live'; |
26 |
lImg.onload = loadGfx; |
27 |
|
28 |
bltImg.src = 'bullet.png'; |
29 |
bltImg.name = 'bullet'; |
30 |
bltImg.onload = loadGfx; |
31 |
|
32 |
winImg.src = 'win.png'; |
33 |
winImg.name = 'win'; |
34 |
winImg.onload = loadGfx; |
35 |
|
36 |
loseImg.src = 'lose.png'; |
37 |
loseImg.name = 'lose'; |
38 |
loseImg.onload = loadGfx; |
Step 23: Set Ticker
The Ticker class provides a centralized "tick", broadcast at a set interval. We can use its tick()
function to run certain code at a regular frequency.
The following code sets the frame rate to 30 and defines the stage as the listener for the ticks.
The TweenJS class will listen to this tick to perform the animations.
1 |
|
2 |
/* Ticker */
|
3 |
|
4 |
Ticker.setFPS(30); |
5 |
Ticker.addListener(stage); |
Step 24: Preload Function
Every time a graphic is loaded this function will run. It will assign each image to a bitmap object and check that all the elements are loaded before proceeding to call addGameView
.
1 |
|
2 |
function loadGfx(e) |
3 |
{
|
4 |
if(e.target.name = 'bg'){bg = new Bitmap(bgImg);} |
5 |
if(e.target.name = 'bg2'){bg2 = new Bitmap(bg2Img);} |
6 |
if(e.target.name = 'ship'){ship = new Bitmap(sImg);} |
7 |
|
8 |
gfxLoaded++; |
9 |
|
10 |
if(gfxLoaded == 9) |
11 |
{
|
12 |
addGameView(); |
13 |
}
|
14 |
}
|
Step 25: Add Game View
When all the graphics are loaded the addGameView
function is called. This function will add the ship, lives counter, score, and backgrounds to the stage.
1 |
|
2 |
function addGameView() |
3 |
{
|
4 |
ship.x = centerX - 18.5; |
5 |
ship.y = 480 + 34; |
6 |
|
7 |
/* Add Lives */
|
8 |
|
9 |
for(var i = 0; i < 3; i++) |
10 |
{
|
11 |
var l = new Bitmap(lImg); |
12 |
|
13 |
l.x = 248 + (25 * i); |
14 |
l.y = 463; |
15 |
|
16 |
lives.addChild(l); |
17 |
stage.update(); |
18 |
}
|
19 |
|
20 |
/* Score Text */
|
21 |
|
22 |
score = new Text('0', 'bold 14px Courier New', '#FFFFFF'); |
23 |
score.maxWidth = 1000; //fix for Chrome 17 |
24 |
score.x = 2; |
25 |
score.y = 476; |
26 |
|
27 |
/* Second Background */
|
28 |
|
29 |
bg2.y = -480; |
30 |
|
31 |
/* Add gfx to stage and Tween Ship */
|
32 |
|
33 |
stage.addChild(bg, bg2, ship, enemies, bullets, lives, score); |
34 |
Tween.get(ship).to({y:425}, 1000).call(startGame); |
35 |
}
|
Step 26: Move Ship
The player's ship will be mouse controlled, and we use this function to handle that:
1 |
|
2 |
function moveShip(e) |
3 |
{
|
4 |
ship.x = e.stageX - 18.5; |
5 |
}
|
e.stageX
refers to the mouse's x-coordinate, and this function is called whenever the mouse moved.
Step 27: Shoot
Our ship will be able to shoot bullets to destroy and protect itself from enemies. This function will run every time the user clicks the stage and will place a bullet in front of the ship that will be later moved by the update()
function. It also plays a shooting sound.
1 |
|
2 |
function shoot() |
3 |
{
|
4 |
var b = new Bitmap(bltImg); |
5 |
|
6 |
b.x = ship.x + 13; |
7 |
b.y = ship.y - 20; |
8 |
|
9 |
bullets.addChild(b); |
10 |
stage.update(); |
11 |
|
12 |
SoundJS.play('shot'); |
13 |
}
|
Step 28: Add Enemy Function
It wouldn't be a shooter without something to shoot. Here, a setInterval()
is used to create an enemy every 1000 milliseconds (you can change that value in the next step) which is later moved by the update()
function.
1 |
|
2 |
function addEnemy() |
3 |
{
|
4 |
var e = new Bitmap(eImg); |
5 |
|
6 |
e.x = Math.floor(Math.random() * (320 - 50)) |
7 |
e.y = -50 |
8 |
|
9 |
enemies.addChild(e); |
10 |
stage.update(); |
11 |
}
|
Step 29: Start Game
These lines will add the necessary listeners to the stage and timer; this includes mouse events, timed events (via setInterval
) and Ticker events that will update the game every frame.
1 |
|
2 |
function startGame() |
3 |
{
|
4 |
stage.onMouseMove = moveShip; |
5 |
bg.onPress = shoot; |
6 |
bg2.onPress = shoot; |
7 |
|
8 |
Ticker.addListener(tkr, false); |
9 |
tkr.tick = update; |
10 |
|
11 |
timerSource = setInterval('addEnemy()', 1000); |
12 |
}
|
Step 30: Move Background
The background is moved every frame to simulate space travel; when the lower background sprite reaches the stage limit it is moved back to the top, creating an infinite loop.
1 |
|
2 |
function update() |
3 |
{
|
4 |
/* Move Background */
|
5 |
|
6 |
bg.y += 5; |
7 |
bg2.y += 5; |
8 |
|
9 |
if(bg.y >= 480) |
10 |
{
|
11 |
bg.y = -480; |
12 |
}
|
13 |
else if(bg2.y >= 480) |
14 |
{
|
15 |
bg2.y = -480; |
16 |
}
|
Step 31: Move Bullets
The next lines of code check whether there are bullets in stage; if so, the bullets are moved upwards.
1 |
|
2 |
/* Move Bullets */
|
3 |
|
4 |
for(var i = 0; i < bullets.children.length; i++) |
5 |
{
|
6 |
bullets.children[i].y -= 10; |
7 |
}
|
Step 32: Remove Offstage Bullets
Let's add some lines to detect the bullet position, and use this to destroy a bullet when it is no longer visible.
1 |
|
2 |
/* Move Bullets */
|
3 |
|
4 |
for(var i = 0; i < bullets.children.length; i++) |
5 |
{
|
6 |
bullets.children[i].y -= 10; |
7 |
|
8 |
/* Remove Offstage Bullets */
|
9 |
|
10 |
if(bullets.children[i].y < - 20) |
11 |
{
|
12 |
bullets.removeChildAt(i); |
13 |
}
|
14 |
}
|
Step 33: Show Boss
We'll add a big bad boss to the game. When the user reaches a certain score, the boss will appear:
1 |
|
2 |
/* Show Boss */
|
3 |
|
4 |
if(parseInt(score.text) >= 500 && boss == null) |
5 |
{
|
6 |
boss = new Bitmap(bImg); |
7 |
|
8 |
SoundJS.play('boss'); |
9 |
|
10 |
boss.x = centerX - 90; |
11 |
boss.y = -183; |
12 |
|
13 |
stage.addChild(boss); |
14 |
Tween.get(boss).to({y:40}, 2000) //tween the boss onto the play area |
15 |
}
|
Step 34: Move Enemies
The enemies, like the bullets, are also moved every frame. This code finds all the enemies in the stage using the enemies
container, and moves them each 5px downwards.
1 |
|
2 |
/* Move Enemies */
|
3 |
|
4 |
for(var j = 0; j < enemies.children.length; j++) |
5 |
{
|
6 |
enemies.children[j].y += 5; |
Step 35: Remove Off-Stage Enemies
We also check the enemies' positions to destroy them when no longer visible.
1 |
|
2 |
/* Move Enemies */
|
3 |
|
4 |
for(var j = 0; j < enemies.children.length; j++) |
5 |
{
|
6 |
enemies.children[j].y += 5; |
7 |
|
8 |
/* Remove Offstage Enemies */
|
9 |
|
10 |
if(enemies.children[j].y > 480 + 50) |
11 |
{
|
12 |
enemies.removeChildAt(j); |
13 |
}
|
Step 36: Bullet - Enemy Collision
The bullets in the container are tested for collision with the enemies; when this happens, both are removed from the stage, a sound is played and the score is updated.
1 |
|
2 |
for(var k = 0; k < bullets.children.length; k++) |
3 |
{
|
4 |
/* Bullet - Enemy Collision */
|
5 |
|
6 |
if(bullets.children[k].x >= enemies.children[j].x && bullets.children[k].x + 11 < enemies.children[j].x + 49 && bullets.children[k].y < enemies.children[j].y + 40) |
7 |
{
|
8 |
bullets.removeChildAt(k); |
9 |
enemies.removeChildAt(j); |
10 |
stage.update(); |
11 |
SoundJS.play('explo'); |
12 |
score.text = parseFloat(score.text + 50); |
13 |
}
|
Step 37: Bullet - Boss Collision
The following code handles the boss collisions, it uses the same method used in the bullet-enemy collision loop. Here we use the bossHealth
variable to determine when the boss is defeated.
1 |
|
2 |
/* Bullet - Boss Collision */
|
3 |
|
4 |
if(boss != null && bullets.children[k].x >= boss.x && bullets.children[k].x + 11 < boss.x + 183 && bullets.children[k].y < boss.y + 162) |
5 |
{
|
6 |
bullets.removeChildAt(k); |
7 |
bossHealth--; |
8 |
stage.update(); |
9 |
SoundJS.play('explo'); |
10 |
score.text = parseInt(score.text + 50); |
11 |
}
|
12 |
}
|
Step 38: Ship - Enemy Collision
Here we check whether an enemy collides with the player's ship; if it does, a sound is played, a life is removed, and the ship is animated.
1 |
|
2 |
/* Ship - Enemy Collision */
|
3 |
|
4 |
if(enemies.hitTest(ship.x, ship.y) || enemies.hitTest(ship.x + 37, ship.y)) |
5 |
{
|
6 |
enemies.removeChildAt(j); |
7 |
lives.removeChildAt(lives.length); |
8 |
ship.y = 480 + 34; |
9 |
Tween.get(ship).to({y:425}, 500) |
10 |
SoundJS.play('explo'); |
11 |
}
|
12 |
}
|
Step 39: Check for Win or Lose
The player wins when the boss loses all its health and loses if all their own lives are lost. The next lines detect those situations and call an alert function using the correct parameter.
1 |
|
2 |
/* Check for win */
|
3 |
|
4 |
if(boss != null && bossHealth <= 0) |
5 |
{
|
6 |
alert('win'); |
7 |
}
|
8 |
|
9 |
/* Check for lose */
|
10 |
|
11 |
if(lives.children.length <= 0) |
12 |
{
|
13 |
alert('lose'); |
14 |
}
|
15 |
}
|
Step 40: Alert
The Alert shows the player information about the status of the game; it is shown when a game event is reached. It removes the game listeners and shows the appropiate message.
1 |
|
2 |
function alert(e) |
3 |
{
|
4 |
/* Remove Listeners */
|
5 |
|
6 |
stage.onMouseMove = null; |
7 |
bg.onPress = null; |
8 |
bg2.onPress = null; |
9 |
|
10 |
Ticker.removeListener(tkr); |
11 |
tkr = null; |
12 |
|
13 |
timerSource = null; |
14 |
|
15 |
/* Display Correct Message */
|
16 |
|
17 |
if(e == 'win') |
18 |
{
|
19 |
win = new Bitmap(winImg); |
20 |
win.x = centerX - 64; |
21 |
win.y = centerY - 23; |
22 |
stage.addChild(win); |
23 |
stage.removeChild(enemies, boss); |
24 |
}
|
25 |
else
|
26 |
{
|
27 |
lose = new Bitmap(loseImg); |
28 |
lose.x = centerX - 64; |
29 |
lose.y = centerY - 23; |
30 |
stage.addChild(lose); |
31 |
stage.removeChild(enemies, ship); |
32 |
}
|
33 |
|
34 |
bg.onPress = function(){window.location.reload();}; |
35 |
bg2.onPress = function(){window.location.reload();}; |
36 |
stage.update(); |
37 |
}
|
Step 41: Test



Save your work (if you haven't) and open the HTML file in the browser to see your HTML5 game working!
Conclusion
You've learned how to create a Space Shooter game with all its basic features, try to expand it using what you already know. A good start would be making the enemies or boss shoot back at the player.
I hope you liked this tutorial, thank you for reading!