I thought I would share my implementation of the shooter script. There are two small improvements: 1) wrapping the isFiring bool with a setter function and 2) refactoring the random fire rate code into a local method returning timeToNextProjectile.
From the Player script OnFire() instead of setting the isFiring bool directly you just call the SetFiring() and pass in the bool value. By making isFiring bool private you do not have to hide it in the Inspector. and you protect the Player class from any internal changes to the bool in the Shooter class.
Refactoring the random fite rate into its own function makes the coroutine FireContinuously() more readable.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Shooter : MonoBehaviour
{
[Header("General")]
[SerializeField] GameObject projectilePrefab;
[SerializeField] float projectileSpeed = 10f;
[SerializeField] float projectileLifetime = 5f;
[SerializeField] float baseFiringRate = 0.2f;
[Header("AI")]
[SerializeField] bool useAI;
[SerializeField] float firingRateVariance = 0f;
[SerializeField] float minimumFiringRate = 0.1f;
bool isFiring;
Coroutine firingCoroutine;
void Start()
{
SetFiring(useAI);
}
void Update()
{
Fire();
}
public void SetFiring(bool startFiring)
{
isFiring = startFiring;
}
void Fire()
{
if (isFiring && firingCoroutine == null)
{
firingCoroutine = StartCoroutine(FireContinuously());
}
else if (!isFiring && firingCoroutine != null)
{
StopCoroutine(firingCoroutine);
firingCoroutine = null;
}
}
float GetRandomFireTime()
{
float timeToNextProjectile = Random.Range(baseFiringRate - firingRateVariance,
baseFiringRate + firingRateVariance);
timeToNextProjectile = Mathf.Clamp(timeToNextProjectile, minimumFiringRate, float.MaxValue);
return timeToNextProjectile;
}
IEnumerator FireContinuously()
{
while (true)
{
GameObject instance = Instantiate(projectilePrefab,
transform.position,
Quaternion.identity);
Rigidbody2D rb = instance.GetComponent<Rigidbody2D>();
if (rb != null)
{
rb.velocity = transform.up * projectileSpeed;
}
Destroy(instance, projectileLifetime);
yield return new WaitForSeconds(GetRandomFireTime());
}
}
}