It’s time now to add another powerup. This next one will be a speed boost. The first thing we notice is the basic behavior of our new powerup game object is exactly the same as the triple shot. Recall this script.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TripleShotPowerUp : MonoBehaviour
{
[SerializeField] private float mySpeed = 3f;
private void Start()
{
Destroy(this.gameObject, 5);
}
private void Update()
{
transform.Translate(Vector3.down * Time.deltaTime * mySpeed);
}
private void OnTriggerEnter2D(Collider2D other)
{
if ( other.tag == "Player" ) { Destroy(this.gameObject); }
}
}
Other than the name, there is nothing different about what this game object is doing and what the new one will do. As soon as it starts, we want to set the timed Destroy()
. We want it to go down the screen. Finally, if it collides with the player, we want to destroy it immediately. In fact, we can just attach this script to our new powerup, and it works exactly the way we want. However, so as to not be offensive, we can go ahead and change the script name and the class name to just PowerUp.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PowerUp : MonoBehaviour
{
[SerializeField] private float mySpeed = 3f;
private void Start()
{
Destroy(this.gameObject, 5);
}
private void Update()
{
transform.Translate(Vector3.down * Time.deltaTime * mySpeed);
}
private void OnTriggerEnter2D(Collider2D other)
{
if ( other.tag == "Player" ) { Destroy(this.gameObject); }
}
}
As previously discussed, once the player collides with something, the player itself decides what to do about. In the player class we do this by checking the game object tag. Therefore, the first thing we need to do is make sure every different type of object that will collide with the player has a unique tag. We’ve already set our existing game objects with “Enemy” and “TripleShotPU” so let’s give our new powerup a tag of “SpeedPU.”
Previously, our OnTriggerCollide2D()
method had two if()
statements. This would make a third and we know there are more coming. So, let’s convert to a switch statement.
private void OnTriggerEnter2D(Collider2D other)
{
switch (other.tag)
{
case "Enemy":
TakeDamage();
break;
case "TripleShotPU":
if (!tripleShot) { StartCoroutine(PowerUpTripleShot()); }
break;
case "SpeedPU":
if (speedUp == 0) { StartCoroutine(PowerUpSpeed()); }
break;
default:
break;
}
}
We start by checking the tag value. We then branch accordingly. For the powerups, we additionally check if the powerup is already enabled or not. If not, enable it with a coroutine. Since we want the powerups to be short lived, we can assume for now each powerup will be controlled via a coroutine. The coroutine for the speed powerup will be similar to the triple shot coroutine. First the powerup is enabled, then the coroutine yields for the allotted time. Upon return, the powerup is disabled.
private IEnumerator PowerUpSpeed()
{
speedUp = 3;
yield return new WaitForSeconds(speedUpTimer);
speedUp = 0;
}
This leaves the Spawn Manager. Spawning the enemy is already separated from spawning the powerup(s) so let’s continue in that manner. However, instead of giving every powerup its own manager, we will have just one and have it randomize which powerup is produced. Now, we could spin something off the tags like we did in the Player class, but there is an easier way. Instead of trying to track each one individually, we can just store them in an array. Then, instead of trying to randomize which powerup is chosen by tag we can just randomize the array index which is easy. We then pluck out whatever powerup prefab is stored at that index.
private IEnumerator SpawnPowerUp()
{
while (keepSpawning)
{
GameObject powerUp = Instantiate( powerUpPrefabs[Random.Range(0, powerUpPrefabs.Length)]
, new Vector3(Random.Range(-11f, 11f), 8, 0)
, Quaternion.identity);
if (powerUp != null) { powerUp.transform.parent = powerUpContainer.transform; }
yield return new WaitForSeconds(Random.Range(5f, 10f));
}
}
The code above could possibly be improved for readability, but its conciseness limits the difficulty. So long as the powerups continue to work in the same way, they can be added with no further changes needed to the spawn manager.
So, power up, and power on!