InvokeRepeating repeating too often with OnTriggerEnter

hey all,

Two unit objects (shooting butterflies in this case) both have sphere colliders with isTrigger checked. Let’s call them BF A and BF B.

When BF B collides with the sphere trigger for BF A, BF A runs some code to instantiate a homing missile aimed at BF B and send it towards it.

I am using Invoke Repeating to allow BF A to repeatedly instantiate projectiles at BF B until B is destroyed or exits the trigger sphere.

I am using the time and repeatRate variables in InvokeRepeating to try to control the fire rate. Instead, the unit firing fires off many, many projectiles in rapid succession. I am assuming that InvokeRepeating is getting restarted due to the trigger collision but am not sure quite how that’s happening. I am managing the collisions with layers so I don’t think there is unwanted collision happening but that might be an issue. Finally, here is the code for the shooter:

public var projectile:Transform;
public var projectileSpeed:float = 0.0;
public var delay:float = 0.0;
public var fireRate:float = 1.0;
public var myLayer: int; 
public var myColorTag: String; 
public var alreadyFiring: boolean;

//private var projectileCount:int = 0;
 
// Current player variable
private var target:GameObject = null;
 
function OnTriggerEnter(other:Collider)
{
    if(other.gameObject.tag != myColorTag && other.gameObject.tag != "environment" && other.gameObject.tag != "explosion" && other.gameObject.tag != "Resource" && other.gameObject.tag != "projectile")
    {  
    	if (alreadyFiring == true)

		{ CancelInvoke("Shoot"); alreadyFiring = false; } 
		
		if (alreadyFiring == false) {

		InvokeRepeating("Shoot", delay, fireRate);

		}
    
        // Store current player
        // NB this assume that you have only one player because it will overwrite second player
        target = other.gameObject;
        InvokeRepeating("Shoot", delay, fireRate); 
        
    }
}
 
function OnTriggerExit(other:Collider)
{
    if(other.gameObject.tag != myColorTag && other.gameObject.tag != "environment" && other.gameObject.tag != "explosion" && other.gameObject.tag != "Resource" && other.gameObject.tag != "projectile")
  //   print ("tested true for tag to shoot. mycolortag: " + myColorTag);
    
    {
        // Remove reference
        target = null;
        CancelInvoke("Shoot");
    }
}
 
function Shoot()
{ 
	alreadyFiring = true;
    var shootClone = Instantiate(projectile, transform.position, transform.rotation);
    // Set projectile velocity
    shootClone.gameObject.layer = myLayer; 
    
    var setLayerScript = shootClone.GetComponent(spawnDamageExplosion);
    if(setLayerScript) setLayerScript.myLayerForExplosion = myLayer;
//    print ("spawned missile and initialized explosion layer to" + myLayer);
    
   
    shootClone.rigidbody.velocity = (target.transform.position - transform.position).normalized * projectileSpeed;
}

1 Answer

1

The problem is InvokeRepeating isn’t getting restarted due to the trigger collision. Instead, it ‘instance a new function call’ once u call it. Line 31 in your script cause u invoke a new ‘function instance’ each time on trigger enter. That’s why your script firing so many missles.

Usually I used StartCoroutine instead of InvokeRepeating to avoid the situation that I forgot to cancel the invoke or invoke a method multiple times.
such as

IEnumerator StarFireMissle(float timeInterval)
{
while(firing)
{
FireTarget();
yield return new WaitForSeconds(timeInterval);
}
}

Thank you! I had an intuition that I might be creating many copies of the function. I've used startcoroutine before and will rewrite with that. Appreciate your taking the time!