Toggle Menu
Home Blog Projects Newsletter

Space defender - part 3 - the enemies

Space defender game & code displayed

In the last part we created the player's ship and made it move. In this part we'll create the enemies and make them move. And then we'll shoot them down!

Creating the enemies

We're going to do something similar as when we created the bullets. We're going to create a template enemy that we'll clone every time we want to create a new enemy. We also need to keep track of the enemies via an array because there can be more than one at the same time.

But first, we'll create the method that creates the enemy. Add the following code after the createBullet method:

let enemyTemplate: PIXI.Graphics | undefined = undefined;
function createEnemy() {
    if(!enemyTemplate) {
        enemyTemplate = new Graphics();
        enemyTemplate
            .poly([
                0, 0,
                50, 0,
                25, 25,
            ])
            .fill(0xFF6666);
    }

    const enemy = enemyTemplate.clone();
    enemy.x = 25 + (Math.random() * 480) - 50;
    enemy.y = -50;

    return enemy;
}

As you can see, it's pretty similar to the createBullet method. We create a template enemy that we clone every time we want to create a new enemy. We then position the enemy at a random x position at the top of the screen. The enemy has the same shape as the player's ship, but it's red and upside down.

We specify the spawn location of the enemy by setting the x and y properties. The x property is set to a random value between 25 and 480 - 50, so that the enemy is always within the game screen. The y property is set to -50, so that the enemy is just outside the screen, and will move into it.

Next up, we need to call this method to create a new enemy every few seconds.

Spawning enemies

We'll use the setInterval method for this. Add the following code right after where we defined the bullets array:

const enemies: PIXI.Graphics[] = [];

const enemySpawnInterval = 2500;
function spawnEnemy() {
    if(!document.hasFocus()) {
        return;
    }
    const enemy = createEnemy();
    enemies.push(enemy);
    app.stage.addChild(enemy);
}

setInterval(spawnEnemy, enemySpawnInterval);
spawnEnemy();

We create a new array called enemies to keep track of all the enemies. We then create a new variable called enemySpawnInterval that specifies how often we want to spawn a new enemy. We then create a new method called spawnEnemy that creates a new enemy and adds it to the enemies array and the stage. We then call this method every enemySpawnInterval milliseconds using the setInterval method.

Cool, now we have enemies spawning at the top of the screen every 2.5 seconds. But they're not moving yet, and we don't see them because they're out of the screen. Let's fix that.

Moving the enemies

We need to update the enemies' position in the game loop. Add the following code to your game loop, right under where we update the bullets' position:

for(let i = 0; i < enemies.length; i++) {
    const enemy = enemies[i];
    enemy.y += 2.5;

    if(enemy.y > app.screen.height + 50) {
        app.stage.removeChild(enemy);
        enemies.splice(i, 1);
    }
}

This part of the code will loop over all the enemies, update their position by moving them down 2.5 pixels and check if they are out of bounds. If they are, we remove them from the stage and the enemies array.

Nice! if you run your game now you'll see enemies spawning at the top of the screen and moving down.

Now it's time to shoot them down!

Shooting the enemies

Add the following code to your game loop, right under where we update the enemies position:

for(let i = 0; i < bullets.length; i++) {
    const bullet = bullets[i];
    for(let j = 0; j < enemies.length; j++) {
        const enemy = enemies[j];
        if(
            bullet.x > enemy.x &&
            bullet.x < enemy.x + 50 &&
            bullet.y > enemy.y &&
            bullet.y < enemy.y + 25
        ) {
            app.stage.removeChild(bullet);
            app.stage.removeChild(enemy);
            bullets.splice(i, 1);
            enemies.splice(j, 1);
        }
    }
}

This part of the code will loop over all the bullets and all the enemies and check if a bullet hits an enemy. If it does, we remove both the bullet and the enemy from the stage and their respective arrays.

You could optimize this code by breaking out of the inner loop when a bullet hits an enemy, but for now, this is fine. You could also combine the bullet position update loop with the bullet hit check loop, but I like to keep them separate for clarity of this tutorial.

And that's it! You now have a game where you can move left and right, shoot bullets, and shoot down enemies. In the next part, we're going to add some HUD elements to the game and keep track of the player's score, level and lives.

Recent articles

Make a simple game using PixiJS and TypeScriptPixiJS setup with Vite and TypeScriptHow Your Coding Skills Can Make a Real Difference in the WorldA guide to writing clean and readable codeAccomplish more with the "Cult of Done"Host your web app for free on Cloudflare PagesFinally got around to making a website for myself