Polishing The Game: Ammo Counter

Clint Wagoner
4 min readMar 31, 2023

--

Let’s limit the ammo count for the player, requiring strategy and poise to be successful. In the next article, we will go over creating an ammo refill power-up.

Setting up the UI

So the first thing we need to do is design the UI to have an ammo count text. We do this by creating a new TMP Pro object, sizing it, and anchoring it to a corner. In this case, I chose to add it right under the Boost gauge.

Right-click your UI canvas and select UI > Text — Text Mesh Pro. Set your font, size, location, and anchor. Call it ‘AmmoText’.

If you need a more detailed tutorial on setting up text objects, check this out. Now let’s get to scripting the text counter.

Scripting The Ammo Counter

We will need to adjust two different scripts to make this work, the ‘Shooting’ and the ‘UIManager’ scripts. Let’s start with the UIManager script as it needs less work.

First, create a new exposed private TMP_Text variable called ‘_ammoText’ and a private int variable called ‘_ammoCount’:

public class UIManager : MonoBehaviour
{
[SerializeField] private TMP_Text _ammoText;
private int _ammoCount;
}

Next, Let’s create a new public method called ‘UpdateAmmoCount()’:

public class UIManager : MonoBehaviour
{
[SerializeField] private TMP_Text _ammoText;
private int _ammoCount;

public void UpdateAmmoCount(int ammo)
{
_ammoCount = ammo;
_ammoText.text = _ammoCount.ToString() + " Ammo Left";
}

}

In the editor, select your canvas and drag the AmmoText object to the slot in your UIManager component called ‘Ammo Text’ to assign it.

And that is all we need to do in the ‘UIManager’.

Next, let’s hop over into the ‘Shooting ’script and create an exposed variable here called ‘_maxAmmo’. Let’s also create a private int variable here that is also called ‘_ammoCount’:

public class Shooting : MonoBehaviour
{
[SerializeField] private int _maxAmmo = 15;
public bool hasTripleShot = false;

}

Now, let’s tell the ‘Shooting ’script to only shoot if we have ammo. We can do this in the Update() method where we originally called the ‘Shoot()’ method:

public class Shooting : MonoBehaviour
{
[SerializeField] private int _maxAmmo = 15;
public bool hasTripleShot = false;

//Change this...
void Update()
{
if (Input.GetButtonDown("Fire1")) Shoot();
}

//To this.
void Update()
{
if (_ammoCount == 0) return;
else if (Input.GetButtonDown("Fire1")) Shoot();
}


}

Finally, let’s hop down into the Shoot() method and have it update the ammo count for the ‘UIManager’:

public class Shooting : MonoBehaviour
{
[SerializeField] private int _maxAmmo = 15;
public bool hasTripleShot = false;

void Update()
{
if (_ammoCount == 0) return;
else if (Input.GetButtonDown("Fire1")) Shoot();
}

public void Shoot()
{
Instantiate(_laserPrefab, transform.position + new Vector3(0, 1.5f, 0), Quaternion.identity);
_ammoCount--;//reduce ammo by one
_uiManager.UpdateAmmoCount(_ammoCount);//Send new ammo count to the UI
}

}

And there you go! Now we are counting down the ammo by one unit every time the player fires a shot. In the next tutorial, we will go over how to recharge the ammo using an ammo refill power-up.

I’m attaching my UIManager and Shooting scripts below.

Thanks for reading!

UIManager Script:

using UnityEngine;
using TMPro;
using UnityEngine.UI;
using System.Collections;
using System;

public class UIManager : MonoBehaviour
{
[SerializeField] private TMP_Text _scoreText;
[SerializeField] private TMP_Text _ammoText;
[SerializeField] private TMP_Text _restartText;
private byte _alpha;
private int _ammoCount;

[SerializeField] private int _score;
[SerializeField] private Sprite[] _livesSprites;
[SerializeField] private Image _livesImage;

public void AddScore(int points)
{
_score += points;
_scoreText.text = "Score: " + _score.ToString();
}

public void UpdateLives(int currentLives)
{
_livesImage.sprite = _livesSprites[currentLives];
}

public void UpdateAmmoCount(int ammo)
{
_ammoCount = ammo;
_ammoText.text = _ammoCount.ToString() + " Ammo Left";
}

public void OnGameOver()
{
StartCoroutine(EnableRestartText());
}

IEnumerator EnableRestartText()
{
yield return new WaitForSeconds(1f);
while (_alpha < 255)
{
_alpha++;
yield return new WaitForSeconds(0.01f);
_restartText.color = new Color32(255, 0, 0, _alpha);
}

}
}

Shooting Script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Shooting : MonoBehaviour
{
[Header("Object Assignments")]
[SerializeField] private GameObject _laserPrefab;
[SerializeField] private GameObject _tripleShotPrefab;
[SerializeField] private GameObject _muzzleFlash;
[SerializeField] private GameObject _LeftWingFlash;
[SerializeField] private GameObject _RightWingFlash;
[SerializeField] private GameObject _laserContainer;
[SerializeField] private GameObject _tripleShotContainer;
private AudioSource _laserSound;
private AudioSource _tripleShotSound;
private GameManager _gameManager;
private UIManager _uiManager;

[Header("Cool Downs")]
[SerializeField] private float _bulletWaitTime = 0.25f;

[Header("Flags")]
[SerializeField] private int _maxAmmo = 15;
[SerializeField] private bool _canShoot = true;
public bool hasTripleShot = false;
private int _ammoCount;

private void Start()
{
_laserSound = GameObject.Find("LaserSound").GetComponent<AudioSource>();
if (_laserSound == null) Debug.LogError("_laserSound is Null");

_tripleShotSound = GameObject.Find("TripleShotSound").GetComponent<AudioSource>();
if (_tripleShotSound == null) Debug.LogError("_tripleShotSound is Null");

_gameManager = FindObjectOfType<GameManager>();
if (_gameManager == null) Debug.LogError("_gameManager is Null");

_uiManager = FindObjectOfType<UIManager>();
if (_uiManager == null) Debug.LogError("_uiManager is Null");

_ammoCount = _maxAmmo;
}

void Update()
{
if (!_gameManager.gamePaused && _canShoot && Input.GetButtonDown("Fire1")) Shoot();
}

public void Shoot()
{
if (ammoCount == 0)
{
_noAmmoSound.Play();
return;
}

if (!hasTripleShot)
{
_laserSound.Play();
_muzzleFlash.GetComponent<ParticleSystem>().Play();
Instantiate(_laserPrefab, transform.position + new Vector3(0, 1.5f, 0), Quaternion.identity);
ammoCount--;
_uiManager.UpdateAmmoCount(ammoCount);
}
else
{
_tripleShotSound.Play();
_muzzleFlash.GetComponent<ParticleSystem>().Play();
_LeftWingFlash.GetComponent<ParticleSystem>().Play();
_RightWingFlash.GetComponent<ParticleSystem>().Play();
Instantiate(_tripleShotPrefab, transform.position + new Vector3(0, 0.5f, 0), Quaternion.identity);
ammoCount--;
_uiManager.UpdateAmmoCount(ammoCount);
}
_canShoot = false;
StartCoroutine(BulletWaitTimer());
}

IEnumerator BulletWaitTimer()
{
yield return new WaitForSeconds(_bulletWaitTime);
_canShoot = true;
}

public void TripleShotActive()
{
hasTripleShot = true;
}

public void DisableTripleShot()
{
hasTripleShot = false;
}
}

--

--