Nerd For Tech
Published in

Nerd For Tech

Space Shooter Refactoring: Delegates

This article will show how to implement the Observer Design Pattern into the Space Shooter using Action and Func Delegates discussed in the previous article.

Bit of a joke since the adding and removing methods on Delegates can be known as subscribing and unsubscribing. But on a serious note, there is a lot of code blocks ahead.

Since implementing the Delegates will require changing a fair amount of the code, I will show the primary examples to get the base implementation across. If you want to see all of the changes, you can look at the GitHub repository.

Game Manager

To access Delegates, we need to use the System namespace. For the GameManager script, we will add variables for the score, Player GameObject, and Player script. It makes more sense to move the score to the GameManager since the Player could become disabled or destroyed. And we will have any script that needs a reference to the Player GameObject or script to ask for it from the GameManager.

We will use Actions to notify the UIManager when the Escape key has been pressed and pass the updated score value to the UIManager. We will use a Func to retrieve the Player GameObject from the Player.

In Start, we send the score value to the UIManager, set the playerObj to the retrieved GameObject, and if it is not null, we set playerScript to the Player script component on it.

If the Escape key is pressed, OnPauseMenu will be called if there is a listener.

The first method will return the Player GameObject retrieved by the GameManager script and pass it to the Delegates that the method is listening to. The second method does the same as the first but for the Player script. The final method will update the score by the amount given and then send it to the UIManager.

In OnEnable and OnDisable, we subscribe and unsubscribe the methods to the other scripts’ Delegates.

Spawn Manager

Since the SpawnManager script uses System and UnityEngine, we need to define which Random we mean to use; we want the UnityEngine Random.

The SpawnManager will now keep a List of active Enemies for the HomingMissile script to grab and use as targets and use an int to track the number of living Enemies in the scene. We will use Actions to start the flashing of the next wave text and update the wave text on the UIManager. We will use Funcs to get back the Enemy and Power of the correct type from the PoolManager.

In Start, we send the current wave and total waves to the listening UIManager.

In Update, change it to use the new enemiesActive variable for checking if there are Enemies still alive.

In StartSpawning, we now call OnUpdateWaves passing the current and total waves to the listening UIManager. Then call OnNextWave to tell the UIManager to flash the next wave text.

The first method will return the List of active Enemies to the Delegates that the method is listening to. The second method increases the active Enemy count and adds Enemy GameObject to the List of active Enemies. The final method decreases the active Enemy count and removes Enemy GameObject from the List of active Enemies.

In the SpawnWaveRoutine, we change it to use OnGetEnemy to retrieve the Enemy GameObject from the PoolManager and then add the Enemy to the active Enemy List.

In OnEnable and OnDisable, we subscribe and unsubscribe the methods to the other scripts’ Delegates.

Pool Manager

The PoolManager script is registering and de-registering to all of the get requests.

Enemy

In the Enemy script, we use Actions to remove the Enemy as a target and the active Enemy List. We tell the AudioManager what sound to play, send how much to increase the score, and pass the amount of damage to the Player when colliding. We use Funcs to get the correct Laser or Weapon from the PoolManager and get the Player script from the GameManager.

In Init, we use the OnGetPlayerScript to get the Player script.

In OnTriggerEnter2D, we check that the Player is active in the scene and then call OnScored to send the amount to increase the score.

In FireLaser, we change it to use OnGetLaser to retrieve the Laser from the PoolManager.

Since the Delegates are using the event keyword to lock them to this script, we need to create methods for the scripts that are inheriting to call them for getting the Laser or Weapon from the PoolManager and send the sound effect to the AudioManager.

In the DisableRoutine, we use OnDestroyed to send the script’s GameObject to remove it from being a target and from the active Enemy List.

Enemies are now added and removed from the Active Enemy List as they are spawned and destroyed.

Player

In the Player script, we will use Actions to tell the camera to shake and update the lives images, the thruster bar, the ammo count, and the missile count in the UI. Remove the Player from the Enemy missile target, tell the GameManager the Player is dead, and pass an audio clip to be played by the AudioManager. The Funcs will be used to get the Lasers, Weapons, and Explosion from the PoolManager.

In Init, the UI updates are changed to the corresponding Actions.

In Update, we change it to use OnGetWeapon to retrieve the Missile from the PoolManager and update the Missile UI with OnUpdateMissiles.

In FireLaser, we change it to use OnGetLaser for the Triple Shot and Laser to retrieve the Laser from the PoolManager and use OnGetWeapon to get Omni-Shot.

In ChangeLives, we change it to call OnCameraShake when the Player takes damage and updates the UI with OnUpdateLives.

We change the existing methods to use the Actions to update the UI, create a method to return the Player GameObject, and create a method to disable the Player script when the game is won so the Player can’t be hurt or move anymore.

In OnEnable and OnDisable, we subscribe and unsubscribe the methods to the other scripts’ Delegates.

After adding the register and de-register to the UIManager and CameraShake scripts, the game works just like before but without the Player grabbing everyone’s script components.

Homing Missile

In the HomingMissile script, we will change it to request the List of active Enemies, damage the Player without retrieving the Player script from the collided object and get the correct Explosion from the PoolManager when destroyed.

In AssignEnemyTarget, we change it to use OnGetTargetList to request the List of active Enemies from the SpawnManager.

In OnTriggerEnter2D, we change it to use the OnDamagePlayer to damage the Player.

In OnEnable and OnDisable, we subscribe and unsubscribe the RemoveTarget method to the Enemy and Player destroyed Delegates and change it to use OnGetExplosion to retrieve the correct Explosion from the PoolManager.

Now the Missiles work as they did before but using Delegates.

--

--

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
Kyle W. Powers

Kyle W. Powers

Unity Developer, Software Engineer, Game Developer