Video icon 64
Build your coding skills with practical video courses from Tuts+. Start your free trial today.
Advertisement

Create a Simple Space Shooter Game in HTML5 With EaselJS

by
This post is part of a series called Shoot-'Em-Up.
An Introduction to FlashPunk: Creating a Spaceship Shoot-'Em-Up
Build a Stage3D Shoot-'Em-Up: Sprite Test

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:



Click to play the demo.


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.

 
<!DOCTYPE html> 
<html> 
	<head> 
		<title>Shooter</title> 
	</head> 
	<body> 
	</body> 
</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.

 
<!DOCTYPE html> 
<html> 
	<head> 
		<title>Shooter</title> 
		 
		<style>*{-webkit-tap-highlight-color: rgba(0, 0, 0, 0);}</style> 
	 
	</head> 
	<body> 
	</body> 
</html>

Step 6: JavaScript Libraries

The following code adds the necessary JavaScript libraries required for our app to work.

 
<!DOCTYPE html> 
<html> 
	<head> 
		<title>Shooter</title> 
		 
		<style>*{-webkit-tap-highlight-color: rgba(0, 0, 0, 0);}</style> 
 
		<script src="easel.js"></script> 
		<script src="Tween.js"></script> 
		<script src="sound.js"></script> 
		<script src="Main.js"></script> 
	</head> 
	<body> 
	</body> 
</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.

 
<!DOCTYPE html> 
<html> 
	<head> 
		<title>Shooter</title> 
		 
		<style>*{-webkit-tap-highlight-color: rgba(0, 0, 0, 0);}</style> 
 
		<script src="easel.js"></script> 
		<script src="Tween.js"></script> 
		<script src="sound.js"></script> 
		<script src="Main.js"></script> 
 
	</head> 
	<body onload="Main();"> 
	</body> 
</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.

 
<!DOCTYPE html> 
<html> 
	<head> 
		<title>Shooter</title> 
		 
		<style>*{-webkit-tap-highlight-color: rgba(0, 0, 0, 0);}</style> 
 
		<script src="easel.js"></script> 
		<script src="Tween.js"></script> 
		<script src="sound.js"></script> 
		<script src="Main.js"></script> 
 
	</head> 
	<body onload="Main();"> 
		<canvas id="Shooter" width="320" height="480"></canvas> 
	</body> 
</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.)

 
/* Define Canvas */ 
 
var canvas; 
var stage;

Step 11: Background

The next variables store the background images. Two tiled images are used to create an infinitely scrolling background.

 
/* Background */ 
 
var bgImg = new Image(); 
var bg; 
var bg2Img = new Image(); 
var bg2;

Step 12: Ship

This is the Ship that will be used as the player character or hero.

 
/* Ship */ 
 
var sImg = new Image(); 
var ship;

Step 13: Enemy

Multiple enemies will be on the stage; they will use this as the source graphic.

 
/* Enemy */ 
 
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.

 
/* Boss */ 
 
var bImg = new Image(); 
var boss;

Step 15: Lives

The "life" icon. Three lives are given at the start, and you lose one when hit by an enemy.

 
/* Lives */ 
 
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.

 
/* Bullets */ 
 
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.

 
/* Alert */ 
 
var winImg = new Image(); 
var loseImg = new Image(); 
var win; 
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.

 
var lives = new Container(); //stores the lives gfx 
var bullets = new Container(); //stores the bullets gfx 
var enemies = new Container(); //stores the enemies gfx 
var bossHealth = 20; 
var score; 
var gfxLoaded = 0; //used as a preloader, counts the already loaded items 
var centerX = 160; 
var centerY = 240; 
var tkr = new Object(); //used as a Ticker listener 
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.

 
function Main() 
{ 
	//code... 
}

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.

 
/* Link Canvas */ 
	 
canvas = document.getElementById('Shooter'); 
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.

 
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.
 
/* Sound */ 
 
SoundJS.addBatch([ 
		{name:'boss', src:'boss.mp3', instances:1}, 
		{name:'explo', src:'explo.mp3', instances:10}, 
		{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.

 
/* Load GFX */ 
 
bgImg.src = 'bg.png'; 
bgImg.name = 'bg'; 
bgImg.onload = loadGfx; 
 	 
bg2Img.src = 'bg2.png'; 
bg2Img.name = 'bg2'; 
bg2Img.onload = loadGfx; 
 	 
sImg.src = 'ship.png'; 
sImg.name = 'ship'; 
sImg.onload = loadGfx; 
 
eImg.src = 'enemy1.png'; 
eImg.name = 'enemy'; 
eImg.onload = loadGfx; 
 
bImg.src = 'boss.png'; 
bImg.name = 'boss'; 
bImg.onload = loadGfx; 
 
lImg.src = 'live.png'; 
lImg.name = 'live'; 
lImg.onload = loadGfx; 
 
bltImg.src = 'bullet.png'; 
bltImg.name = 'bullet'; 
bltImg.onload = loadGfx; 
 
winImg.src = 'win.png'; 
winImg.name = 'win'; 
winImg.onload = loadGfx; 
 
loseImg.src = 'lose.png'; 
loseImg.name = 'lose'; 
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.

 
/* Ticker */ 
 
Ticker.setFPS(30); 
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.

 
function loadGfx(e) 
{ 
	if(e.target.name = 'bg'){bg = new Bitmap(bgImg);} 
	if(e.target.name = 'bg2'){bg2 = new Bitmap(bg2Img);} 
	if(e.target.name = 'ship'){ship = new Bitmap(sImg);} 
	 
	gfxLoaded++; 
	 
	if(gfxLoaded == 9) 
	{ 
		addGameView(); 
	} 
}

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.

 
function addGameView() 
{ 
	ship.x = centerX - 18.5; 
	ship.y = 480 + 34; 
	 
	/* Add Lives */ 
	 
	for(var i = 0; i < 3; i++) 
	{ 
		var l = new Bitmap(lImg); 
		 
		l.x = 248 + (25 * i); 
		l.y = 463; 
		 
		lives.addChild(l); 
		stage.update(); 
	} 
	 
	/* Score Text */ 
	 
	score = new Text('0', 'bold 14px Courier New', '#FFFFFF'); 
	score.maxWidth = 1000;	//fix for Chrome 17 
	score.x = 2; 
	score.y = 476; 
	 
	/* Second Background */ 
	 
	bg2.y = -480; 
	 
	/* Add gfx to stage and Tween Ship */ 
	 
	stage.addChild(bg, bg2, ship, enemies, bullets, lives, score); 
	Tween.get(ship).to({y:425}, 1000).call(startGame); 
}

Step 26: Move Ship

The player's ship will be mouse controlled, and we use this function to handle that:

 
function moveShip(e) 
{ 
	ship.x = e.stageX - 18.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.

 
function shoot() 
{ 
	var b = new Bitmap(bltImg); 
	 
	b.x = ship.x + 13; 
	b.y = ship.y - 20; 
	 
	bullets.addChild(b); 
	stage.update(); 
	 
	SoundJS.play('shot'); 
}

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.

 
function addEnemy() 
{ 
	var e = new Bitmap(eImg); 
	 
	e.x = Math.floor(Math.random() * (320 - 50)) 
	e.y = -50 
	 
	enemies.addChild(e); 
	stage.update(); 
}

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.

 
function startGame() 
{ 
	stage.onMouseMove = moveShip; 
	bg.onPress = shoot; 
	bg2.onPress = shoot; 
	 
	Ticker.addListener(tkr, false); 
	tkr.tick = update; 
	 
	timerSource = setInterval('addEnemy()', 1000); 
}

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.

 
function update() 
{ 
	/* Move Background */ 
	 
	bg.y += 5; 
	bg2.y += 5; 
	 
	if(bg.y >= 480) 
	{ 
		bg.y = -480; 
	} 
	else if(bg2.y >= 480) 
	{ 
		bg2.y = -480; 
	}

Step 31: Move Bullets

The next lines of code check whether there are bullets in stage; if so, the bullets are moved upwards.

 
/* Move Bullets */ 
	 
	for(var i = 0; i < bullets.children.length; i++) 
	{ 
		bullets.children[i].y -= 10; 
	}

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.

 
/* Move Bullets */ 
	 
	for(var i = 0; i < bullets.children.length; i++) 
	{ 
		bullets.children[i].y -= 10; 
		 
		/* Remove Offstage Bullets */ 
		 
		if(bullets.children[i].y < - 20) 
		{ 
			bullets.removeChildAt(i); 
		} 
	}

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:

 
/* Show Boss */ 
	 
	if(parseInt(score.text) >= 500 && boss == null) 
	{ 
		boss = new Bitmap(bImg); 
				 
		SoundJS.play('boss'); 
				 
		boss.x = centerX - 90; 
		boss.y = -183; 
				 
		stage.addChild(boss); 
		Tween.get(boss).to({y:40}, 2000)   //tween the boss onto the play area 
	}

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.

 
/* Move Enemies */ 
	 
	for(var j = 0; j < enemies.children.length; j++) 
	{ 
		enemies.children[j].y += 5;

Step 35: Remove Off-Stage Enemies

We also check the enemies' positions to destroy them when no longer visible.

 
/* Move Enemies */ 
	 
	for(var j = 0; j < enemies.children.length; j++) 
	{ 
		enemies.children[j].y += 5; 
		 
		/* Remove Offstage Enemies */ 
		 
		if(enemies.children[j].y > 480 + 50) 
		{ 
			enemies.removeChildAt(j); 
		}

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.

 
for(var k = 0; k < bullets.children.length; k++) 
{ 
	/* Bullet - Enemy Collision */ 
	 
	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) 
	{ 
		bullets.removeChildAt(k); 
		enemies.removeChildAt(j); 
		stage.update(); 
		SoundJS.play('explo'); 
		score.text = parseFloat(score.text + 50); 
	}

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.

 
/* Bullet - Boss Collision */ 
			 
	if(boss != null && bullets.children[k].x >= boss.x && bullets.children[k].x + 11 < boss.x + 183 && bullets.children[k].y < boss.y + 162) 
	{ 
		bullets.removeChildAt(k); 
		bossHealth--; 
		stage.update(); 
		SoundJS.play('explo'); 
		score.text = parseInt(score.text + 50); 
	} 
}

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.

 
/* Ship - Enemy Collision */ 
		 
	if(enemies.hitTest(ship.x, ship.y) || enemies.hitTest(ship.x + 37, ship.y)) 
	{ 
		enemies.removeChildAt(j); 
		lives.removeChildAt(lives.length); 
		ship.y = 480 + 34; 
		Tween.get(ship).to({y:425}, 500) 
		SoundJS.play('explo'); 
	} 
}

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.

 
/* Check for win */ 
	 
	if(boss != null && bossHealth <= 0) 
	{ 
		alert('win'); 
	} 
	 
	/* Check for lose */ 
	 
	if(lives.children.length <= 0) 
	{ 
		alert('lose'); 
	} 
}

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.

 
function alert(e) 
{ 
	/* Remove Listeners */ 
		 
	stage.onMouseMove = null; 
	bg.onPress = null; 
	bg2.onPress = null; 
	 
	Ticker.removeListener(tkr); 
	tkr = null; 
	 
	timerSource = null; 
	 
	/* Display Correct Message */ 
	 
	if(e == 'win') 
	{ 
		win = new Bitmap(winImg); 
		win.x = centerX - 64; 
		win.y = centerY - 23; 
		stage.addChild(win); 
		stage.removeChild(enemies, boss); 
	} 
	else 
	{ 
		lose = new Bitmap(loseImg); 
		lose.x = centerX - 64; 
		lose.y = centerY - 23; 
		stage.addChild(lose); 
		stage.removeChild(enemies, ship); 
	} 
	 
	bg.onPress = function(){window.location.reload();}; 
	bg2.onPress = function(){window.location.reload();}; 
	stage.update(); 
}

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!

Advertisement