Working projectile scripts do not work due to if condition

Hi there,

I’ve successfully managed to have my player shoot fireballs from his hands. However, this is done on a key press.

I now want my enemy to fire fireballs, and so I tried to use exactly the same script. However, the fireball stays in its position and does not move forward. The reason for this is because the firing of this fireball happens when the enemy is a certain distance away from my player. Therefore, I believe the fireball keeps instantiating itself, keeping each one from moving forward. I tested this by adding a sound, and the sound rapidly repeats multiple times, indicating that the fireballs are being instantiated far too often.

Here is a code snippet from my first script, which is attached to my enemy game object:

void PatrolAndChase()
	{
				// calculate the distance to the player
				int distanceToPlayer = (int)Vector3.Distance (player.transform.position, transform.position);
		
				// calculate vector direction to the player
				Vector3 directionToPlayer = transform.position - player.transform.position;
		
				// calculate the angle between AI forward vector and direction toward player
				// we use Mathf.Abs to store the absolute value (i.e. always positive)
				int angle = (int)Mathf.Abs (Vector3.Angle (transform.forward, directionToPlayer));
	**if
		(distanceToPlayer > 60) {
						StartCoroutine (Shoot ());
				}**
				// if player is within 30m and angle is greater than 130 then begin chasing the player
				else if (distanceToPlayer < 30 && angle > 130) {
						// move towards the players position
						//MoveTowards (player.transform.position);
			
						// attack the player ONLY if not already attacking
						if (!attacking && distanceToPlayer < 15) {
								StartCoroutine (Attack ());
						} else if (!attacking) {
								// player is "out of sight"
								MoveTowards (player.transform.position);
						}
				} 
		else {
						// patrol
						Patrol ();
			
						// if attacking, then toggle to stop
			
				}

		}

The code surrounded by asterisks is what we’re interested in. This calls the Shoot coroutine, which is in the same script and is as follows:

IEnumerator Shoot()
	{
		yield return new WaitForSeconds(2);
		attacking  = true;
   		StartCoroutine (BowserFireball.Instance.Fire());
		attacking  = false;

	}

We can see here that this coroutine is calling yet another coroutine from my BowserFireball script. I’ve also added a WaitForSeconds clause to have the fireball sequence happen every 2 seconds. However, the routinely firing of the fireball does not work. Here is the BowserFireball script:

using System.Collections;

public class BowserFireball : MonoBehaviour {
	public static BowserFireball Instance { get; private set; }
	
	public Rigidbody projectile;
	public AudioClip fireballSound;
	public GameObject target;
	
	void Awake()
	{
		if (Instance == null) 
		{
			Instance = this;
		}
		else
		{
			Destroy(gameObject);
		}
	}
	
	public IEnumerator Fire()
	{
		animation.CrossFade("fireball (1)", 0.2F);

		audio.PlayOneShot (fireballSound);
		
		Rigidbody instantiatedProjectile = Instantiate (projectile,
		                                                transform.position,
		                                                transform.rotation)
			as Rigidbody;
		instantiatedProjectile.velocity = transform.TransformDirection (new Vector3 (0, 0, 50));
		yield return new WaitForSeconds(2);
		Destroy (instantiatedProjectile.gameObject);
	}
}

This script governs the firing of the fireball and how it destroys itself. It is attached to an empty game object called FireballSpawn, which is a child of my enemy.

As stated previously, these scripts (with a few tweaks) worked for my player, but not for my enemy (because of the condition that the enemy fires the fireball constantly if he’s a certain distance away from my player, I’m assuming). I need my enemy to fire a fireball every 1.5-3 seconds or so, so that 1): it is more routine and not a constant flow of fireballs and 2) (and most importantly): my fireballs can actually move and the noise he makes happens once per fire.

Your time and support would be thoroughly appreciated,

Many thanks!

I’m guessing a bit because the code I need to see to nail down the problem is not here. I’m guessing that you are calling PatrolAndChase() frequently…perhaps every frame or FixedUpdate(). For each one of those calls, you are generating a new coroutine. So if your game is running at approximately 60 fps, in the 2 seconds that Shoot() waits before firing, you stack, your code will stack up 120 coroutines. At the end of 2 seconds, you will start to see calls to BowserFireball.Instance.Fire() at approximately one frame apart. So you are going to need to figure out some mechanism so that Shot() is not call while it is currently running. Something as simple as a boolean flag:

IEnumerator Shoot()
{
   shooting = true;
   yield return new WaitForSeconds(2);
   attacking  = true;
   StartCoroutine (BowserFireball.Instance.Fire());
   attacking  = false;
   shooting = false;
}  

Then your check would become:

 if (!shooting && distanceToPlayer > 60)