Unity Tutorial: How to Make a Game Like Space Invaders

In this Unity tutorial, you’ll learn how to make a classic 2D space shooting game similar to Space Invaders. By Najmm Shora.

4.9 (9) · 3 Reviews

Download materials
Save for later
Share
You are currently viewing page 3 of 5 of this article. Click here to view the first page.

Making the Invaders Shoot Lasers

You'll use a variant of the Bullet prefab for the invaders. Navigate to RW/Prefabs and find the EnemyBullet. It's the same as Bullet, except the sprite points in the opposite Y direction and its layer is set to Enemy.

Select EnemyBullet. Notice the Speed of Bullet is set to -200. This ensures the bullet moves in the opposite direction of the cannon bullets but with the same magnitude.

The Inspector window for the EnemyBullet prefab

In the game, only invaders at the front of the swarm shoot laser bullets. To achieve this, you'll use the BulletSpawner prefab located in RW/Prefabs.

You'll instantiate as many of them as the invader column count. You'll also make the bullet spawners follow the invader Transforms at the front of the swarm.

This will ensure that when firing, the bullets will appear to be coming from the front row invaders.

Before you do that, you need a way to get an invader Transform at a specific row and column from the invaders array inside InvaderSwarm.

Open the InvaderSwarm.cs script and add the following line after the InvaderType struct declaration:

internal static InvaderSwarm Instance;

This helps turn the InvaderSwarm into a Singleton.

Then paste the following right above Start:

internal Transform GetInvader(int row, int column)
{
    if (row < 0 || column < 0
        || row >= invaders.GetLength(0) || column >= invaders.GetLength(1)) 
    {
        return null;
    }

    return invaders[row, column];
}

private void Awake()
{
    if (Instance == null) 
    {
        Instance = this;
    }
    else if (Instance != this) 
    {
        Destroy(gameObject);
    }
}

GetInvader returns the invader Transform at the row and column index of invaders. Awake turns the InvaderSwarm into a Singleton by ensuring that when the game starts, only one instance of InvaderSwarm will be alive.

Now, select the BulletSpawner prefab and take a look at the Inspector. Notice it has Bullet Spawner attached to it.

There's also a Kinematic Rigidbody 2D, a Box Collider 2D and the layer is set to Enemy. You won't add colliders to the invaders, but rather use this collider to detect hits from the cannon bullets.

The Inspector window for BulletSpawner.

In your code editor, open the BulletSpawner.cs script attached to BulletSpawner and add the following inside the class:

internal int currentRow;
internal int column;

[SerializeField] 
private AudioClip shooting;

[SerializeField] 
private GameObject bulletPrefab;

[SerializeField] 
private Transform spawnPoint;

[SerializeField] 
private float minTime;

[SerializeField]
private float maxTime;

private float timer;
private float currentTime;
private Transform followTarget;

internal void Setup()
{
    currentTime = Random.Range(minTime, maxTime);
    followTarget = InvaderSwarm.Instance.GetInvader(currentRow, column);
}

private void Update()
{
    transform.position = followTarget.position;

    timer += Time.deltaTime;
    if (timer < currentTime) 
    {
        return;
    }

    Instantiate(bulletPrefab, spawnPoint.position, Quaternion.identity);
    GameManager.Instance.PlaySfx(shooting);
    timer = 0f;
    currentTime = Random.Range(minTime, maxTime);
}

Here's a code breakdown:

  • currentTime represents the time to wait until shooting the next bullet. It's set to a random value between minTime and maxTime.
  • currentRow and column link a bullet spawner with an invader. The column is set once and won't change. But, as you'll see later, currentRow updates if the player's bullets hit this spawner.
  • Inside Setup(), you set followTarget by calling GetInvader from the InvaderSwarm instance using currentRow and column. You also set an initial value to currentTime.
  • Inside Update, you update the position of the bullet spawner to match the followTarget.position. In addition, you increment the timer until it reaches currentTime. When this happens, you create a bullet at spawnPoint.position while playing the shooting sound effect, followed by resetting timer and currentTime.

Save everything. Return to Unity and open BulletSpawner in Prefab Mode. Ensure the following values are set for Bullet Spawner:

  • Shooting to InvaderBullet located at RW/Sounds.
  • Bullet Prefab to EnemyBullet located at RW/Prefabs.
  • Spawn Point to the SpawnPoint Transform which is the only child of BulletSpawner.
  • Min Time to 1 and Max Time to 10.

The Inspector showing the Bullet Spawner script.

To use the BulletSpawner, you need to go back to the InvaderSwarm.cs script.

First, paste the following line at the end of all the variable declarations:

[SerializeField] 
private BulletSpawner bulletSpawnerPrefab;

Then, inside Start, add the following lines at the end:

for (int i = 0; i < columnCount; i++)
{
    var bulletSpawner = Instantiate(bulletSpawnerPrefab);
    bulletSpawner.transform.SetParent(swarm.transform);
    bulletSpawner.column = i;
    bulletSpawner.currentRow = rowCount - 1;
    bulletSpawner.Setup();
}

In this code, you create a bullet spawner and set it up. You instantiate bulletSpawner for each column of the swarm and set its column and currentRow followed by calling its Setup method. You also parent the bulletSpawner to the Swarm to prevent clutter in the Hierarchy.

Save everything and go back to Unity. Select Game Controller from the Hierarchy and set the Bullet Spawner Prefab for Invader Swarm to BulletSpawner, located in RW/Prefabs.

Save and Play. You now have invaders who shoot bullets at the player.

The swarm is now shooting laser bullets at the cannon.

Notice that both bullets disappear when an invader bullet and cannon bullet collide. The invader bullet disappears when it hits the cannon and the cannon bullet disappears when it hits a bullet spawner. They disappear because OnCollisionEnter2D calls DestroySelf inside Bullet.

There's one thing missing, however, and that's explosions. :] You'll add them next.

Adding Explosions

Navigate to RW/Prefabs. Notice the Explosion prefab. It's a simple GameObject with a pre-made sprite animation you'll use for the explosion visuals.

Now, open GameManager.cs again. Add the following after declaring sfx:

[SerializeField] 
private GameObject explosionPrefab;

[SerializeField] 
private float explosionTime = 1f;

[SerializeField] 
private AudioClip explosionClip;

internal void CreateExplosion(Vector2 position)
{
    PlaySfx(explosionClip);

    var explosion = Instantiate(explosionPrefab, position,
        Quaternion.Euler(0f, 0f, Random.Range(-180f, 180f)));
    Destroy(explosion, explosionTime);
}

CreateExplosion creates an explosion at position with a random rotation along the Z-axis, and destroys it after explosionTime seconds.

To use CreateExplosion, add the following line at the end of DestroySelf inside the Bullet class:

GameManager.Instance.CreateExplosion(transform.position);

Save all. Return to Unity and select Game Controller from the Hierarchy. For the Game Manager set:

  • Explosion Prefab to Explosion located in RW/Prefabs.
  • Explosion Clip to Explosion located in RW/Sounds.

The Game Manager component in the Inspector window

Save the scene and Play. You now have explosions. :]

Firing bullets now yields explosions

Currently, the bullets don't affect the invaders or the cannon. In the following sections, you'll add scores and lives.

Adding Scores and Lives

Did you notice those super retro UI labels in the game view? Right now they're just deadweight. It's time to get them working so that there are goals and consequences to give this game meaning.