• Home
  • Who’s Zeke?

ZekeChan.net

Game Development - Build, Learn, Earn

Asteroids HTML5 Game Tutorial Part 1: Project Setup & Moving The Player Ship

October 24, 2015 By Zeke 9 Comments

Back in November 1979, Atari launched Asteroids, their all-time best selling game. Over time, Atari sold more than 100,000 units of Asteroids video game machines. Although that number seems small compared to games available on mobile phones and tablets, back then, it was a phenomenal success.

Lyle Rains, vice president of the coin-operated games division, came up with the basic game idea: Players would control the movement of a small spaceship while shooting asteroids to clear an area of space. Ed Logg, the programmer working on Asteroids, added the idea that the asteroids would repeatedly get smaller as the player shot them. Also, to keep players alert, he also added 2 UFOs: large, slow moving ones that shot randomly; and smaller fast moving ones that would aim at the player’s ship.

Players would control their ship with 5 buttons: rotate left, rotate right, thrust, fire, and hyperspace. When a player used hyperspace, their ship would be transported to a random spot on the screen. Hopefully they wouldn’t collide with an asteroid or UFO. For every 10,000 points a player scores, they will be rewarded with an extra life.

On November 14, 1982, 15-year-old Scott Safran became the official top scorer in Asteroids with a score of 41,336,440. That high score remained unbeatable for 28 years until April 5, 2010. John McAllister beat the world record in 58 hours. Eventually, he toppled the 1982 world record with a high score of 41,338,740.

Tutorial overview

In this tutorial series, we’ll be looking at how to create an Asteroids like game. Here’s a screen shot of what the final game should look like:

asteroids-01

The steps for this series includes:

  1. Project setup
  2. Player ship
  3. Creating a single screen game world
  4. Adding asteroids
  5. Adding player lives
  6. Adding sounds
  7. The main menu state

Game mechanics

Before we jump right in and start coding our game, it’s always good to figure out how our game works and the features we want to include.

Player ship:

  • Always starts right at the centre of our game world
  • The player ship is invulnerable for 3 seconds upon respawning after it crashes with an asteroid
  • 5 lives when a game starts
  • Extra life given every 10,000 points

Asteroids:

  • 4 asteroids when a game starts
  • 2 asteroids added to each completed round
  • A maximum of 20 large asteroids is allowed to appear
  • Asteroid numbers stop increasing after a score of 60,000 is reached

Scoring:

  • Large asteroid: 20 points
  • Medium asteroid: 50 points
  • Small asteroid: 100 points

Project Files

Click here to download the project files that we’ll be using in this tutorial. You will find the following in the zip file:

  • index.html, the html canvas where the game will be displayed
  • /js/phaser.min.js, version 2.4.0 of the Phaser framework
  • /js/game.js, the game source codes
  • /assets/graphics/asteroidLarge.png
  • /assets/graphics/asteroidMedium.png
  • /assets/graphics/asteroidSmall.png
  • /assets/graphics/bullet.png
  • /assets/graphics/ship.png

Here’s a quick tutorial on how to set up a Phaser project.

Loading assets

Let’s start by loading all our game graphics. After the states object declaration, add in the highlighted code below from lines 10-17:

6
7
8
9
10
11
12
13
14
15
16
17
var states = {
    game: "game",
};
 
var graphicAssets = {
    ship:{URL:'assets/ship.png', name:'ship'},
    bullet:{URL:'assets/bullet.png', name:'bullet'},    
    
    asteroidLarge:{URL:'assets/asteroidLarge.png', name:'asteroidLarge'},
    asteroidMedium:{URL:'assets/asteroidMedium.png', name:'asteroidMedium'},
    asteroidSmall:{URL:'assets/asteroidSmall.png', name:'asteroidSmall'},
};

In the code we just added, we’re declaring a new object called graphicAssets. Within the graphicAssets object, we declare 5 properties for each asset. Each property is an object containing 2 properties: the URL property that points to a relative path to our graphic files and the name property that is a unique string or key to identify which graphic asset to use.

Next we’ll need to preload these graphic assets into our game state. Add the following highlighted codes from lines 26-31:

23
24
25
26
27
28
29
30
31
32
gameState.prototype = {
    
    preload: function () {
        game.load.image(graphicAssets.asteroidLarge.name, graphicAssets.asteroidLarge.URL);
        game.load.image(graphicAssets.asteroidMedium.name, graphicAssets.asteroidMedium.URL);
        game.load.image(graphicAssets.asteroidSmall.name, graphicAssets.asteroidSmall.URL);
        
        game.load.image(graphicAssets.bullet.name, graphicAssets.bullet.URL);
        game.load.image(graphicAssets.ship.name, graphicAssets.ship.URL);
    },

The game.load method is used load all external content such as Images, Sounds, Texture Atlases and data files. In the above code, we’re loading the PNG files for the asteroids, ship and bulllet.

The load.image method requires 2 arguments with an optional third argument:

  • key (string) – The unique asset name of this image file. This name is used in our code later on to identify which image to load in our game.
  • url (string) – The URL where the image file is located.
  • overwrite (boolean <optional>, false by default) – If set to true, this will overwrite an asset if there is an existing key.

At line 26 for example, the compiler will look up the reference for graphicAssets.asteroidLarge.name and graphicAssets.asteroidLarge.URL then replace it with the string values we have assigned to the large asteroid’s name and URL at line 14. Line 26 will then be interpreted like this:

26
        game.load.image('asteroidLarge', 'assets/asteroidLarge.png');

Adding the player ship

Next we’ll add the player ship. Start off by adding the following code after the graphicAssets object:

19
20
21
22
var shipProperties = {
    startX: gameProperties.screenWidth * 0.5,
    startY: gameProperties.screenHeight * 0.5,
};

A new object called shipProperties is declared and will contain all the properties for our player ship. At this time, we only have 2 properties:

  • startX: the x-position of the ship whenever the ship resets
  • startY: the y-position of the ship whenever the ship resets

Next, we’ll declare a  new property in the gameState object called shipSprite to reference our player ship:

24
25
26
var gameState = function (game){
    this.shipSprite;
};

After the update function, add in the following highlighted codes from lines 47-51:

43
44
45
46
47
48
49
50
51
    update: function () {
        
    },
    
    initGraphics: function () {
        this.shipSprite = game.add.sprite(shipProperties.startX, shipProperties.startY, graphicAssets.ship.name);
        this.shipSprite.angle = -90;
        this.shipSprite.anchor.set(0.5, 0.5);
    },

Line 48 is where we add the ship sprite to our game world. Calling the game.add.sprite function will make our sprite appear on screen at the specified x and y positions. Each time we add a new sprite, we will need to have at least 3 parameters:

  • x: the x coordinate of the sprite
  • y: the y coordinate of the sprite
  • key: the image used as a texture by this display object

By default, at 0 degrees rotation, a sprite always faces right. We will want our sprite to be facing upwards so we set the angle to -90 degrees in line 49.

Also, to ensure that our sprite rotates along the correct centre point, we set it’s anchor to 50% of its width and height.

Now, we need to call the initGraphics function to add our ship sprite. Add the following in the create function:

39
40
41
    create: function () {
        this.initGraphics();
    },

You should now see something like this:asteroids-02

You can download the source codes up to this point here.

Adding a physics body

Let’s declare a few more properties for our ship:

19
20
21
22
23
24
25
26
var shipProperties = {
    startX: gameProperties.screenWidth * 0.5,
    startY: gameProperties.screenHeight * 0.5,
    acceleration: 300,
    drag: 100,
    maxVelocity: 300,
    angularVelocity: 200,
};

Here’s a brief description of each property:

  • acceleration: how fast the ship will increase it’s velocity
  • drag: friction that slows down the ship
  • maxVelocity: the maximum movement velocity for our ship
  • angularVelocity: how fast our ship can rotate

Each of these properties will be applied to the ship’s physics body which we will add on next.

After the initGraphics function, add the following:

57
58
59
60
61
62
63
    initPhysics: function () {
        game.physics.startSystem(Phaser.Physics.ARCADE);
        
        game.physics.enable(this.shipSprite, Phaser.Physics.ARCADE);
        this.shipSprite.body.drag.set(shipProperties.drag);
        this.shipSprite.body.maxVelocity.set(shipProperties.maxVelocity);
    },

We’re declaring a new function called initPhysics to initialise the arcade physics system and add physics bodies to all our game objects.

To start the physics system, we call the game.physics.startSystem function in line 58 and enter the Phaser arcade physics as its parameter.

Next, we enable the physics body for our shipSprite in line 60 and set the drag (line 61) and maximum movement velocity (line 62) for the sprite.

Going back to our create function, we then call the initPhysics function to enable the physics system and add the physics body to our ship:

43
44
45
46
    create: function () {
        this.initGraphics();
        this.initPhysics();
    },

Controlling our player ship

Now that our ship has a physics body enabled, we can now add some controls to move our ship. Let’s declare a few properties in our gameState object:

28
29
30
31
32
33
34
var gameState = function (game){
    this.shipSprite;
    
    this.key_left;
    this.key_right;
    this.key_thrust;
};

Looking at the code above, we currently have 3 keys used to control our rotation and forward movement of our player ship.

Next, after the initPhysics function, add the following:

70
71
72
73
74
    initKeyboard: function () {
        this.key_left = game.input.keyboard.addKey(Phaser.Keyboard.LEFT);
        this.key_right = game.input.keyboard.addKey(Phaser.Keyboard.RIGHT);
        this.key_thrust = game.input.keyboard.addKey(Phaser.Keyboard.UP);
    },

Each of our 3 key objects are stored in its respective properties. When calling the game.input.keyboard.addKey function, we pass the key code parameter that represents a specific key we are listening for. For example, the LEFT key code value is 37, the RIGHT key code value is 39 and the UP key code value is 38. You can easily Google up the entire list of key codes or look at the Phaser Keyboard.js file.

Next, in our create function, call the initKeyboard function to run the above codes for our keyboard events:

47
48
49
50
51
    create: function () {
        this.initGraphics();
        this.initPhysics();
        this.initKeyboard();
    },

Now to check for the various key presses and add responses to it. After the initKeyboard function, add the following:

77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
    checkPlayerInput: function () {
        if (this.key_left.isDown) {
            this.shipSprite.body.angularVelocity = -shipProperties.angularVelocity;
        } else if (this.key_right.isDown) {
            this.shipSprite.body.angularVelocity = shipProperties.angularVelocity;
        } else {
            this.shipSprite.body.angularVelocity = 0;
        }
        
        if (this.key_thrust.isDown) {
            game.physics.arcade.accelerationFromRotation(this.shipSprite.rotation, shipProperties.acceleration, this.shipSprite.body.acceleration);
        } else {
            this.shipSprite.body.acceleration.set(0);
        }
    },

The checkPlayerInput function will be called every frame loop to check if any of the assigned keys are being pressed.

From lines 78-84, we check whether our left or right key is being pressed. Note that only one key is being checked at any time. When the LEFT key is being pressed, we set the angularVelocity for the ship’s physics body to a negative value. This rotates the ship counter clockwise. If the RIGHT key is being pressed, the ship rotates clockwise. Finally if neither left nor right key is being pressed, the ship stops rotating.

As for the UP or thrust key, we called the arcade physics accelerationFromRotation function to determine how much acceleration there should be for the x and y axis of the ship. When the key is released, the acceleration is set back to 0 so that the drag can take over and eventually stop our ship from moving forward.

Now to add the checkPlayerInput function to our update function:

49
50
51
    update: function () {
        this.checkPlayerInput();
    },

Here’s our work in progress so far. Click on the game world below to activate it if you are unable to move your ship.

You can download the source codes here.

Next week on the 30th October, we’ll look at creating a single screen game world so whenever our ship moves outside the game world, it will reappear on the opposite side.

*Edit: The next part is ready. Let’s move on!

Did you find this post beneficial? Spot any bugs? Do leave a comment and let me know your thoughts.

Filed Under: Game Development, Tutorials Tagged With: asteroids, beginner, getting started, html5, javascript, phaser, retro

Comments

  1. MB says

    November 3, 2015 at 1:05 am

    “After a certain period of time” you get a free ship?? Ace, it’s 10,000 points.

    Reply
    • Zeke says

      November 3, 2015 at 10:45 am

      Hey MB, thanks for noticing that =) I’ve made the correction

      Reply
  2. Joe Henriod says

    November 17, 2015 at 2:39 pm

    I am too the point in the tutorial where the files could be downloaded again. Right now everything looks great in Firefox, but in Chrome and Safari nothing shows up.

    Are there additional steps I need to make to make this project work in Chrome?

    Thank you for the AWESOME tutorial!

    Reply
    • Zeke says

      November 17, 2015 at 10:55 pm

      Hey Joe, are you using Windows or Mac? You will need a local web server running in order to make it work with Chrome and Safari due to security restrictions.

      For Windows, I would suggest WAMP:
      http://www.wampserver.com/en/

      For Mac, I would suggest MAMP:
      https://www.mamp.info/en/

      Both are fairly straight forward to set up run.

      Reply
    • Zeke says

      November 18, 2015 at 11:56 pm

      Alternatively you could try out the Cloud 9 development environment. It’s web based and they do offer a free account:
      https://c9.io/

      Reply
  3. YuanTingHsieh says

    November 28, 2015 at 3:36 pm

    So far I think this tutorial is very helpful.
    Also I find cloud9 very friendly and useful after I give up WAMP.
    Thank you

    Reply
    • Zeke says

      November 28, 2015 at 7:07 pm

      Yes, cloud9 is useful if you cant get a local server up and running locally… WAMP is easy to install but is a pain when it doesn’t work. Glad you find the tutorials helpful =) Feel free to suggest any tutorial topics you’d like covered

      Reply
  4. Stathis says

    December 27, 2016 at 11:48 pm

    Anyone can explain why the ship does not always go straight? If you have it at an angle, and try to to small thrusts, you notice some little slips downwards. This also happens here: https://phaser.io/examples/v2/arcade-physics/asteroids-movement. Could it be some rounding gone wrong?

    Reply
    • Zeke says

      January 16, 2017 at 9:25 pm

      I don’t quite understand what you mean by slipping downward. What I do notice is this: if the x or y velocity is too small, it is reduced to 0 which makes the ship move either vertically or horizontally.

      Reply

Leave a Reply Cancel reply

Your email address will not be published.

Top 5 Posts

  • Asteroids HTML5 Game Tutorial Part 1: Project Setup & Moving The Player Ship
  • Asteroids HTML5 Game Tutorial Part 5: Scoring, levels, sounds & invulnerability
  • Phaser HTML5 Game Tutorial: Build A Pong Game 1: Project Setup
  • Asteroids HTML5 Game Tutorial Part 4: The player ship splits asteroids
  • Asteroids HTML5 Game Tutorial Part 2: Single Screen Game World & Shooting

Copyright © 2018 · ZekeChan.net