Ammo Collectable
Objective: Create an ammo item that adds to the player’s total ammo when the player picks it up.
It’s important to appropriately plan out the design of your code to be scalable. We want to create an Ammo Collectable for our player to pick up and gain more ammo. We do also want to create a Health Collectable in the future, so we will be writing our code with that in mind.
Create a Collectable Class that inherits MonoBehaviour. All Collectables will have a speed (we’ll set it at 3 for now), and an Audio Clip.
In Update(), we translate the Collectable down the screen in real time. If the Collectable reaches -6 on the Y axis which is off screen, delete the Collectable object.
Next, when the player collides with the Collectable, play the Collectable’s audio clip and call OnPickUp() and pass in the player. Since OnPickUp() is a virtual method, depending if the method is overwritten with override, something different may happen than the base method (which is empty for now).
When that’s all done, the Collectable will be destroyed.
private void OnTriggerEnter2D(Collider2D other) {
Player player = other.GetComponent<Player>();
if (player != null) {
AudioSource.PlayClipAtPoint(clip, transform.position);
OnPickUp(player);
Destroy(gameObject);
}
}
protected virtual void OnPickUp(Player player) { }
In our Player class, we have a method called AddAmmoCount that takes in how much ammo you’d like to add to the player’s total and then updates that ammo as well as the ammo display in the HUD. We use this method in AmmoCollectable when we pick up ammo.
public class Player : MonoBehaviour {
//code
public void AddAmmoCount(int count) {
ammoCount += count;
uiManager.UpdateAmmoCount(ammoCount);
}
//code
}
AmmoCollectable inherits and does everything Collectable does. We override OnPickUp() and pass in the player. We call the player’s AddAmmoCount and pass in 5 to add 5 ammo to the player.
Overwriting a parent’s base method is incredibly useful because in the future, when we have health we want to pick up, we will override OnPickUp but instead perform logic to add health to the player. Collectables can do a variety of things when the player picks it up, depending what type it is.
The last part of our code is to go to our SpawnManager and create a GameObject array for our collectables. Then we will write a Coroutine to spawn the AmmoCollectable every 7–15 seconds with a 3 second break in between while spawning
is true.
It will also be spawned at a random location. The AmmoCollectable is element 0 in our collectables array and every time this Coroutine is run, a random element will be chosen. Right now it will always be the AmmoCollectable but when we add the HealthCollectable, it will choose randomly between the two.
[SerializeField] private GameObject[] collectables;
private bool spawning = true;
public void StartSpawning() {
//code
StartCoroutine(SpawnCollectableCoroutine());
}
//code
IEnumerator SpawnCollectableCoroutine() {
WaitForSeconds wait = new WaitForSeconds(3);
yield return wait;
while (spawning) {
WaitForSeconds waitRandom = new WaitForSeconds(Random.Range
(7f, 15f));
yield return waitRandom;
Vector3 posToSpawn = new Vector3(Random.Range(-8f, 8f), 8.5f, 0);
int randomCollectable = Random.Range(0, collectables.Length);
Instantiate(collectables[randomCollectable], posToSpawn,
Quaternion.identity);
}
}
Lastly, we create an animated sprite for the player to pick up. Once we drag in the first sprite into the Hierarchy and have it selected, create a new animation and drag in the sprites into the Animation window.
Make sure the Sprite Renderer’s Sorting Layer is set to Foreground and you add a Rigidbody 2D and a Box Collider 2D. On the Rigidbody2D, set the Gravity Scale to 0 since we’re controlling the movement through code. Edit the box collider to fit the bounds of the sprite. Finally, add the AmmoCollectable script and drag in the Pick Up Ammo audio clip.
Now we can pick up ammo!