I went for a slightly different approach to calculating the delay between shots. Instead of saying what the delay is, I have instead decided to make a “FireRate” variable that says how many bullets can be fired per second. The time delay is then calculated with:
float timeDelay = 1f / fireRate;
Of course this has it’s own drawbacks when fire rate equals or is below 0 but you can prevent this from happening by using the Range attribute.
The below code is my Weapon script. You can Ignore “namespace”, I’m just trying to get in the habit of organising my code.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using StarterAssets;
using UnityEngine.VFX;
using System;
namespace JamesSonneveld.ZED.Gunplay
{
public class Weapon : MonoBehaviour
{
[SerializeField] Camera _FPCamera;
[SerializeField] float _range = 100f;
[SerializeField] float _damage = 10f;
[SerializeField] private VisualEffect _muzzleFlashVFX;
[SerializeField] private GameObject _impactVFX;
[Tooltip("The amount of bullets that can be fired per second. The higher the number, the more bullets that are fired per second")]
[Range(0.01f, 100f)]
[SerializeField] private float _fireRate = 1f;
private Ammo _ammoSlot;
private StarterAssetsInputs _input;
private bool _canShoot = true;
private void Awake()
{
_ammoSlot = GetComponentInParent<Ammo>();
_input = GetComponentInParent<StarterAssetsInputs>();
}
private void Update()
{
if (_input.shoot)
{
Shoot();
}
}
private void Shoot()
{
if (_ammoSlot.GetCurrentAmmoCount() <= 0 || !_canShoot) return;
PlayMuzzleFlash();
ProcessRaycast();
DecreaseAmmoCount();
DelayShot(_fireRate);
}
private void DelayShot(float fireRate)
{
float timeDelay = 1f / fireRate;
StartCoroutine(PauseForSeconds(timeDelay));
}
private IEnumerator PauseForSeconds(float timeToWait)
{
_canShoot = false;
yield return new WaitForSeconds(timeToWait);
_canShoot = true;
}
private void DecreaseAmmoCount()
{
_ammoSlot.ReduceCurrentAmmo();
}
private void PlayMuzzleFlash()
{
_muzzleFlashVFX.Play();
}
private void ProcessRaycast()
{
RaycastHit hit;
bool hasHit = Physics.Raycast(_FPCamera.transform.position, _FPCamera.transform.forward, out hit, _range);
if (hasHit)
{
CreateHitImpact(hit);
EnemyHealth target = hit.transform.GetComponent<EnemyHealth>();
if (target != null)
target.TakeDamage(_damage);
}
else
{
Debug.Log("I have hit air");
}
}
private void CreateHitImpact(RaycastHit hit)
{
Instantiate(_impactVFX, hit.point, Quaternion.identity);
}
}
}