Build a Space Shooter with Phaser3 and JavaScript(Tutorial3)

In this blog post series, I want to unpack building a 2D shooter game using Phaser3.js. Phaser3 provides a robust and fast game framework for early-stage JavaScript developers. In this tutorial, we will work to add aliens to the scene, give them some basic movement, and blowing them up. Sound like a plan? Here’s what we will build.

Please make sure to check out Tutorial 1 to get started with this project. You’ll need to build upon the code and ideas from the previous blog posts. (post 1, post 2)

To see the code in a completed state, feel free to visit this link. Let’s start by making some modifications to the scene class to preload an enemy sprite graphic. The PNG file will represent how the alien should be drawn to screen. We associate the name ‘enemy1’ with our PNG file.


1
2
3
4
5
6
7
8
9
class Scene1 extends Phaser.Scene {

    preload() {
        this.load.image('ship', 'assets/SpaceShooterRedux/PNG/playerShip1_orange.png');
        this.load.image('laser', 'assets/SpaceShooterRedux/PNG/Lasers/laserBlue01.png');
        this.load.image('enemy1', 'assets/SpaceShooterRedux/PNG/Enemies/enemyBlack3.png');
    }

    ...

In the Phaser game framework, we associate moving game entities with sprites. To define a sprite, we build out an enemy class. When we put a sprite into our scene(as the class is constructed), a special function will be called the constructor. We’ve designed the constructor so that we can set the enemy location at a point (x,y) coordinate and connect it to the scene.

In the constructor, we accomplish the following work. We set the texture of the sprite to ‘enemy1’ and set it the position. Next, we connect this sprite to the physics engine of the scene. We’ll use the physics engine to detect when the enemy gets hit by lasers. We also initialize the deltaX factor to 3. It’s not super exciting, but the aliens will shiver from side to side randomly. This, however, is good enough for a simple lesson. After to complete this tutorial, I encourage you to go crazy with making the aliens move any way you want!


1
2
3
4
5
6
7
8
9
10
11
12
13
    class Enemy1 extends Phaser.GameObjects.Sprite {

    constructor(scene, x, y) {
        super(scene, x, y);
        this.setTexture('enemy1');
        this.setPosition(x, y);
        scene.physics.world.enable(this);

        this.gameObject = this;
        this.deltaX = 3;
    }

    ...

Adding movement to aliens

So, we’re ready to start moving some aliens. Let’s do this! We’re going to write three simple methods on the Enemy1 class. Following the pattern of all Photon sprites, the update method will be called every game tick. It’s your job to tell the sprite how to move. Keep in mind, we’re going to do a simple “side to side” behavior randomly. In the update method, we start by picking a number between 0 and 3. If k is 2, we make the sprite move left using the “this.moveLeft()” function. Otherwise, we make it move to the right using “this.moveRight()”


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    update() {
        let k = Math.random() * 4;
        k = Math.round(k);

        if (k == 2) {
            this.moveLeft();
        }
        else if (k == 3) {
            this.moveRight();
        }
    }

    moveLeft() {
        if (this.x > 0) {
            this.x -= this.deltaX;
        }
    }

    moveRight() {
        if (this.x < SCREEN_WIDTH) {
            this.x += this.deltaX;
        }
    }

Make lots of aliens

At this point, you want to see lots of moving aliens. Let’s add the code to the scene class to construct the aliens. In the scene class, the “create” method will be used to construct all objects. This includes our ship and the aliens. Firstly, we create a special collection object called enemies. We’ll use this collection to track the enemies with the physics system. (this.enemies = this.physics.add.group()) On the next line, we create an Array so that we have a simple way to track our enemies that need updating. In the loop, we’re creating 21 aliens, placing them in random locations, and adding them to our collections. (enemies and enemies2)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Scene1 extends Phaser.Scene {

    ...

    create() {
        this.cursors = this.input.keyboard.createCursorKeys();
        this.myShip = new Ship(this, 400, 500);
        this.add.existing(this.myShip);

        // ======= adding enemies ============
        this.enemies = this.physics.add.group();
        this.enemies2 = new Array();

        let k = 0;
        for (k = 0; k < 21; k++) {
            let x = Math.random() * 800;
            let y = Math.random() * 400;

            this.enemy = new Enemy1(this, x, y);
            this.add.existing(this.enemy);
            this.enemies.add(this.enemy);
            this.enemies2.push(this.enemy);
        }
    }

In order to invoke our update code for all enemies, we need to make one more edit to the scene class. In the “update” method, we need to add a loop to call “update” on all enemies


1
2
3
4
5
6
7
8
9
    update() {
        // there's more code related to the ship here

        let j = 0;
        for (j = 0; j < this.enemies2.length; j++) {
            let enemy = this.enemies2[j];
            enemy.update();
        }
    }

At this point, we should see our aliens wiggling on the screen. And there’s much rejoicing!

Aliens go boom! Let’s do collision detection

In the laser class that we built in the last post, we need to make a few edits. Check out the code below. In the constructor of the ShipLaser, we set the texture, position, speed, and store the parent scene in “this.scene.” We connect the laser instance to the physics engine using “scene.physics.world.enable.” In the next line, we tell the game framework to check for collisions between this laser and the enemies. When a collision happens, we handle the hit using the “handleHit” function.


1
2
3
4
5
6
7
8
9
10
11
12
13
    class ShipLaser extends Phaser.GameObjects.Sprite {

    constructor(scene, x, y) {
        super(scene, x, y);
        this.setTexture('laser');
        this.setPosition(x, y);
        this.speed = 10;
        this.scene = scene;

        // check out new code below ...
        scene.physics.world.enable(this);
        scene.physics.add.collider(this, scene.enemies, this.handleHit, null, this);
    }

In the handle hit function, you’ll notice that the laserSprite and enemySprite have been passed as parameters to the method. In Phaser, you can receive these references so that we can define behaviors associated with both sprites. In this case, we’re just going to destroy the objects.


1
2
3
4
    handleHit(laserSprite, enemySprite) {
        enemySprite.destroy(true);
        laserSprite.destroy(true);
    }

Hope this has been helpful. Please let me know if you have any questions.

Space shooter graphic
This entry was posted in game based learning, games, open source, programming, stem. Bookmark the permalink.