2D Galaxy Shooter Post Mortem

Overcoming the challenges

The final boss fight

With the completion of the final boss challenge I have have wrapped up work on the 2D Galaxy Shooter for @GameDevHQ. The work over the past few weeks has been challenging and fun and the core programming frameworks have been no different.

To wrap up work on the 2D Space Shooter we had to complete challenges in two phases. Below is a list of the challenges in each phase. Items highlighted in bold where the more difficult or more interesting challenges and will be discussed in more detail below after each list.

All code for this project is available on GitHub:

Phase 1 challenges:

  • Thrusters — add thrusters that gave the player a speed boost when pressing the left shift key and returning to normal speed when the key was released.
  • Shield Strength — Add a UI element or animation to track the players shield strength and give it 3 charges.
  • Ammo Count — give the player ammo and limit it to 15, show Ammo on the UI.
  • Ammo Power-Up — add a new collectible to the game that would refill the ammo.
  • Health Collectable — Add a health power up and make sure UI updates when player is repaired.
  • Secondary Fire — give the player a new weapon collectible that was rare.
  • Thruster HUD — add a UI element and cooldown system to the thruster.
  • Camera Shake — shake the game camera when the player takes damage.

Secondary Fire

Sonic Shield

The ‘Sonic Shield’ power is an area of affect attack the player can get on rare occasions. Each wave grows taking out all enemies in its path. Great for late game when enemies are spawning like crazy. Initially it seemed as though this was going to be a challenge to make. In reality it was fairly simple to pull of.

First I cloned the shield prefab and updated it to hold the new image. Next I created a prefab that would act as the projectile. The projectile was then animated so that it grew in scale over a certain time frame. I was originally worried that I would need to scale the collider with the sprite, but thanks to Unity that was taken care of for me.

The real work came in the behavior script for the actual weapon. I wanted to reuse the same behavior script that I used for the normal lasers but had to update things to support the new weapon.

For starters the basic lasers are destroyed on collision with another game object and that defeats the purpose of an AOE. So the first thing added to the script was a bool that would control if that specific object would destroy on trigger. I then added a rotation method and a coroutine to destroy the object after a certain time frame.

Only added code to the script

The coroutine is triggered in the start method and rotate is processed only for this AOE object. Normal lasers are not subjected to rotation. While the design time of the prefabs took as long as expected the actual mechanic was surprisingly simple to implement.

Camera Shake

Camera shake is one of those things that is pretty simple in theory but took a little practice to get right. I’m including it in the post mortem because it was my first time using a class instance.

To make the camera shake I added new script to the camera called CameraShake. Full code below:

public class CameraShake : MonoBehaviour
{
public static CameraShake CameraInstance;

[SerializeField] private Transform _camTransform;
private Vector3 _camStartPos;
private float _shakeTime = 0f;
private readonly float _shakeIntensity = 0.3f;

// Start is called before the first frame update
private void Awake()
{
if (CameraInstance == null)
{
CameraInstance = this;
DontDestroyOnLoad(this);
} else
{
Destroy(this);
}
}

private void Start()
{
_camStartPos = _camTransform.localPosition;
}

// Update is called once per frame
private void Update()
{
if (_shakeTime > 0)
{
_camTransform.localPosition = _camStartPos + (Random.insideUnitSphere * _shakeIntensity);
_shakeTime -= Time.deltaTime;
}
else
{
_shakeTime = 0;
_camTransform.position = _camStartPos;
}
}
public void ShakeCamera()
{
_shakeTime = 0.5f;
}
}

A lot of the work was just setting up the camera instance so that it could shake. With the script in place I just had to tell my player to notify the camera that it needed to shake. This was easy since I made the CameraInstance I could now let any other script in the game tell the camera to shake with a simple line of code.

CameraShake.CameraInstance.ShakeCamera();

Phase 2:

The phase two challenges looked pretty simple at first but did have a few curve balls. The challenges included:

  • New Enemy Movement — Created enemies that could move in some new way, instead of just top to bottom
  • Player Ammo — Make the UI show the players ammo as Current/Max
  • Wave System — update the spawn manager to send the enemies in waves.
  • Negative Pickup — create a collectable that was harmful to the player.
  • New Enemy Type — Create an enemy type that shot the player, with unique weapons that moved in different ways.
  • Balance the spawn system — Adjust the spawn system so that made powerful enemies and pickups more rare.
  • Enemy Shields — create enemies with shields.
  • Aggressive Enemy — create an enemy that would ram the player.
  • Smart Enemy — create an enemy that knows it is behind the player and shots in reverse.
  • Enemy Pickup AI — allow enemies to shoot collectables.
  • Pickup Collect — Create method that would pull power-ups to the player when they press “C”.
  • Enemy Dodge — create enemy that would dodge players weapons.
  • Homing Projectile — create a homing missile.
  • Boss AI — create a boss with special abilities that unique abilities.

Wave System and Balanced Spawning

These two systems go hand in hand with one another and utilized the switch statement heavily. To create the wave system I simply added a base enemy counter to the spawn manager that was updated each time an enemy spawned. Once it reached zero the next wave started.

The real work came with balancing the spawns. To this each enemy and power up was placed into a tier system, with Tier 1 being easy and Tier 3 being the hardest or rarest. I then made use of switch statements to determine which one to spawn.

Spawn tier system in action.

BOSS AI

The hardest most rage inducing part of this project ended up being caused by the most trivial thing.

Turrets were a PITA!

The turrets on the boss proved to be a really big pain in the butt. The player tracking was fairly easy and didn’t really take too long. The problem I encountered was caused by the sprites for the ammo. I originally built a prefab that held four lasers per gun. This prefab ended up have a bad pivot point and was causing the lasers to spawn in the middle of space. For days I fought with code, rewriting it, adding offsets, cursing, praying, sacrificing goats (ok, I made that last part up.) and nothing solved the issue. I finally discovered the root cause when I accidently added the normal laser prefab into the boss inspector instead of the intended ammo I had been fighting with. Any below is the relevant tracking code that I think makes this boss so cool.

Turet Tracking

The code above looks as it currently does in my project. I am currently making a pass to clean up code but wanted to share the mess it took to get the turrets working correctly.

Conclusion

I learned SO much from this project and I am still ironing out the final few bugs in the game but I wanted to cover the post mortem while it was fresh in my head. You can check the game out over at Itch.io and see how frustratingly bad it currently is. It is time to move onto the next task for GameDevHQ but this space shooter experience has been a blast.

Turning my passion for video games and 11 years of software development experience into a focus on video game development using Unity3D.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store