Update
is called every frame
StartCoroutine
starts a new coroutine and immediately returns control flow back to the method that called it.
It does not wait until the coroutine has run to completion (that would cause the game to freeze)
Taken together, what your code currently does:
every frame, it starts a new copy of the coroutine waiting for firerate
.
This means you may have dozens of coroutines all waiting in the background.
then, every frame, it fires the gun, without waiting for anything the coroutines do.
What you want is something more like this:
// This is a delay period, not a rate.
// The rate of fire is 1 shot divided by this many seconds.
public float firingPeriod = 10f;
// We start our coroutine only once, when the script starts,
// not spawning a new copy of the coroutine in every frame update.
void Start() {
StartCoroutine(FireLoop());
}
IEnumerator FireLoop() {
// Loop this coroutine as long as the script stays active/enabled:
while(true) {
// Let the game run for some time.
yield return new WaitForSeconds(firingPeriod);
// After waiting, fire.
FireGun();
// Repeat.
}
}