Tutorial: HTML 5 Space Shooter Part 2

In part 2 of this series we're going to be adding a player ship and the ability to control that ship. If you're just joining us, you'll first want to check out part 1 where we set up a scrolling starfield which serves as the background for the game.

We already know what we want to accomplish here so let's jump right in. The first thing we'll do is load in an image for the player's ship. You can use any image you'd like for this, or even make your own, but I'm going with a classic: the Galaga ship. Once you've found an image you'd like to use, save it in the same directory as your html file; I've creatively named mine ship.png.

Now it's time to go to our javascript and get to the coding. We're going to want to add a couple of new variables to our script; so go to the top of the javascript block we created in the last tutorial and add two new variables; one for the ship image (shipImg) and one that will hold a reference to our ship object (ship). Your variable declarations should look similar to this:

<script type="text/javascript">
    var stage;
    var canvas;
    var g;
    var stars;
			
    var ship;
    var shipImg;

With those variables declared, we can now move into our init function and load the image. This is a pretty straight-forward process. All we need to do is instantiate shipImg, give it an onload handler and then set the src property. Add the following code to your init function just after the call to createStarfield and just before the Ticker set up code.

shipImg = new Image();
shipImg.onload = onShipLoaded;
shipImg.src  = "./ship.png";

You'll want to make sure you use your own image name in place of ship.png if you named yours differently. The complete init function should now look similar to this:

function init() {
    canvas = document.getElementById("canvas");
    stage = new Stage(canvas);

    createStarField();  
			
    shipImg = new Image();
    shipImg.onload = onShipLoaded;
    shipImg.src  = "./ship.png";

    Ticker.setFPS(30);
    Ticker.addListener(window);
}

The next step is to define the onShipLoaded function. Here's what that function looks like, followed by a description of what's happening.

function onShipLoaded() {
    ship = new Bitmap(shipImg);
    ship.regX = ship.image.width * 0.5;
    ship.regY = ship.image.height * 0.5;
    ship.x    = 320;
    ship.y 	  = 450;
				
    stage.addChild(ship);
}

The first line inside this function creates a new easeljs Bitmap object. As a parameter, we pass in our shipImg object which has now completed loading the image data. The next two lines simply set the registration point of the ship to be in the middle (defaults to the top left). Next we set the ship's x and y positions within the display and then call stage.addChild(ship) to place the new bitmap on the screen.

If you open the html page in a supporting browser (such as Chrome), you should now see a scrolling starfield and a ship at the bottom center of the display. Pretty cool, but also fairly useless since you can't control it! Let's fix that!

In order to get the ship moving, the first thing we need to do is add a few more variables at the top of our script block. Add the following variables underneath the ship and shipImg variables we created earlier.

var speed = 8;
var moveLeft = false;
var moveRight = false;
var moveUp = false;
var moveDown = false;

These are just one variable to control our ship's speed and four simple boolean variables that we'll use to determine whether or not the ship should move in a specific direction. In order to make use of these, we need to listen for key press and release events in our window. This is easy enough to set up; add the following lines of code to the end of the init function.

document.onkeydown = onKeyDown;
document.onkeyup   = onKeyUp;

I bet you can guess what comes next...defining our onKeyDown and onKeyUp functions! The idea behind these is simple; we want to see which key was pressed (or released) and set the appropriate boolean value based on that key. We'll be focusing our attention on the arrow keys for ship movement.

function onKeyDown(e) {		
    if(!e){ var e = window.event; }
			
    switch(e.keyCode) {
        // left
        case 37: moveLeft = true; moveRight = false;	
        break;					
        // up
        case 38: moveUp = true; moveDown = false;
        break;					
        // right
        case 39: moveRight = true; moveLeft = false;
        break;										
        // down
        case 40: moveDown = true; moveUp = false;
        break;
    }
}
		
function onKeyUp(e) {		
     if(!e){ var e = window.event; }
			
     switch(e.keyCode) {
        // left
        case 37: moveLeft = false; 
        break;					
        // up
        case 38: moveUp = false;
        break;
        // right
        case 39: moveRight = false;
        break;
        // down
        case 40: moveDown = false;
        break;	
    }
}

In the onKeyDown function we set the corresponding boolean to true and also set the opposite one to false; afterall, you can't move both up and down at the same time! In onKeyUp, we set the booleans to false. In both the first thing we do is make sure we've got the event.

In the next step we'll create a new function, checkMovement, and add a call to it inside our tick function so that we can update player movement every frame.

function checkMovement() {
    if(moveLeft)
    {
        ship.x -= speed;
        if(ship.x < 0)
            ship.x = 640;
    }
    else if(moveRight)
    {
        ship.x += speed;
        if(ship.x > 640)
            ship.x = 0;
    }
				
    if(moveUp)
    {
        if(ship.y - speed > 24)
            ship.y -= speed;
    }
    else if(moveDown)
    {
        if(ship.y + speed < 460)
            ship.y += speed;
    }
}

The checkMovement function moves the player ship by a set amount, speed, each frame if the corresponding arrow key is pressed. We set some boundaries in the vertical direction so that the ship cannot move off of the screen. Meanwhile, on the x axis, the player wraps around to the other side of the screen if they go too far to one side or the other. This is a common feature in many classic arcade games.

Now all that's left to do is to add a call to checkMovement in the tick function.

function tick() {
   updateStarField();
   checkMovement();
    stage.update();
}

Great! You can now move the ship around the display using the arrow keys! Well that's pretty neat, but you know what would make this more badass? Bullets. You can't very well have a space shooter without being able to shoot now can you? This is the final thing we'll do for part 2 of this tutorial series, so let's get started!

As before, the first thing we want to do is add a few more variables at the top of our script block.

var BULLET_SPEED = 15;
var bullets;
var bulletG;

The BULLET_SPEED variable is in all caps because it is a constant, unchanging variable. I used 15, but you can use whatever value you like. Next we have a var named bullets. This will be an array which holds all the bullet objects we create. Lastly we have the bulletG variable which will contain the graphics object that draws a bullet (just like the generic g object that draws our stars in part 1).

Let's define these objects at the top of our init function like so:

bullets = new Array();
bulletG = new Graphics();
bulletG.setStrokeStyle(1);
bulletG.beginStroke(Graphics.getRGB(180,0,0));
bulletG.beginFill(Graphics.getRGB(200,200,0));
bulletG.drawCircle(0,0, 3);

All we're doing here is creating the array and graphics object, then setting a few properties on that graphics object. Our bullet will be a small circle with a red outline and yellow center.

Now we'll add firing functionality to the game. When the user presses and releases the space bar we'll call a function, doFire, which will create a new bullet object and add it to both our bullets array and the stage display list. To do this, we need to add another case to our switch statement in onKeyUp.

function onKeyUp(e) {		
     if(!e){ var e = window.event; }
			
     switch(e.keyCode) {
        // left
        case 37: moveLeft = false; 
        break;					
        // up
        case 38: moveUp = false;
        break;
        // right
        case 39: moveRight = false;
        break;
        // down
        case 40: moveDown = false;
        break;	
        // Space bar for firing
        case 32:	doFire();
        break;
    }
}

Next up: define the doFire function.

function doFire() {				
    var bullet = new Shape(bulletG);
    bullet.scaleY = 1.5;
    bullet.x = ship.x;
    bullet.y = ship.y - 30;
    bullets.push(bullet);
				
    stage.addChild(bullet);
}

The first thing this function does is create a new easeljs Shape object, passing in our graphics object as a parameter. Next we adjust the scaleY of the bullet to give it an oblong shape as opposed to a perfect circle. Then we set the x and y position of the bullet just before adding it to our bullets array and lastly to the stage.

If you view the page in your browser, you'll see that pressing the space bar now does indeed add a bullet to the stage. However, it doesn't move yet. In order to get our bullets moving, we'll create a new function, updateBullets, and call it every frame in the tick function just like we did with checkMovement.

function updateBullets() {
    var bLimit = bullets.length - 1;
	
    for(var i = bLimit; i >= 0; --i) {
        bullets[i].y -= BULLET_SPEED;
        if(bullets[i].y < -3) {
            stage.removeChild(bullets[i]);					
            bullets.splice(i, 1)
        }
    }
}

// tick function with added call to updateBullets
function tick() {
    updateStarField();
    updateBullets();
    checkMovement();
    stage.update();
}

The updateBullets function just loops through our array of bullets and updates the y position of each one. It also checks to see if a bullet has moved off of the screen. If so, it removes the bullet from both the bullets array and from the display list.

Congratulations! You are now well on your way to having a full game written with JavaScript and HTML5! In part 3 of this tutorial series we'll add enemies and collision detection!

As usual you can download the source here; thanks for reading!

< Part 1

Bookmark and Share

Leave a Reply

Subscribe to RSS feed FGS5 Badge