2
\$\begingroup\$

I'm getting some attacking to work with my units and I noticed that the coroutines seem to start adding up even after the StopCoroutine(IEnumerator) as need called.

I dug around on ways to perform an attack loop, most of the time I found "Use InvokeRepeating" and "Don't use InvokeRepeating". Since invoke uses reflection it's performance heavy anyways, so I'd rather not go down that road.

How do I get my coroutine to stop? Is it because it's in a while loop inside the coroutine? If so, how do I fashion an attack loop without using invoke?

//Recieves call when a new enemy is added to the list
public void NewEnemyDetected()
{
    if(currentlyAttacking == null)
    {
        SelectEnemyToAttack();
    }
}

//Recieves call when an enemy leaves the collider area
public void EnemyGone()
{
    SelectEnemyToAttack();
}

//Will select an enemy from the array to attack
private void SelectEnemyToAttack()
{
    if(enemyObjects.Count > 0)
    {
        StopCoroutine(AttackEnemy());
        currentlyAttacking = enemyObjects.ElementAt(0);
        isAttacking = true;
        StartCoroutine(AttackEnemy());
    }
    else
    {
        currentlyAttacking = null;
        isAttacking = false;
    }
}

//Partially hacked together attacking loop
private IEnumerator AttackEnemy()
{
    while(isAttacking)
    {
        Vector3 angle = currentlyAttacking.DetectedGameObject.transform.position - transformV.position;
        angle = angle.normalized;
        GameObject projectile = (GameObject)Instantiate(AttackType, transformV.position, transformV.rotation);
        BlasterAttack projectileAttack = projectile.GetComponent<BlasterAttack>();
        projectileAttack.OnCreation(10, player);
        projectile.GetComponent<Rigidbody>().AddForce(angle * 100);
        yield return new WaitForSeconds(1);
    }
    yield return false;
}

Thanks!

\$\endgroup\$
5
\$\begingroup\$

StopCoroutine takes an IEnumerator object (the routine you want to stop) as parameter.

Here's:

StopCoroutine(AttackEnemy());

AttackEnemy will return a new IEnumerator object, so any other coroutine created before won't be stopped (they are different objects).

The right way to stop is to store a reference to the currently running coroutine, for example:

IEnumerator attackEnemy = AttackEnemy();
StartCoroutine(attackEnemy);

....

StopCoroutine(attackEnemy);

Side note looking at the comments:

  1. Yes string version is slower and does use reflection
  2. Even without considering performances, IEnumerator overload is more flexible (It hasn't always been there a was a serious limitation). In fact you can have multiple running coroutine created using the same method and selectively stop only one of them.
\$\endgroup\$
0
\$\begingroup\$

Turns out I need to call the method by name with a string instead of the method itself to stop the coroutine.

 StartCoroutine("AttackEnemy");
 ...
 StopCoroutine("AttackEnemy");
\$\endgroup\$
  • \$\begingroup\$ You can use either by string, or keep a reference to the Coroutine object you're getting as a return value from StartCoroutine. Then pass said reference into StopCoroutine to stop the coroutine. \$\endgroup\$ – bummzack Mar 28 '15 at 7:23
  • \$\begingroup\$ Ah, how do you get the reference back from the coroutine? It was my understanding that it did not actually return a reference? \$\endgroup\$ – Douglas Gaskell Mar 28 '15 at 20:06
  • \$\begingroup\$ StartCoroutine returns a Coroutine Object, which is an accepted parameter for StopCoroutine (at least in Unity 5) \$\endgroup\$ – bummzack Mar 28 '15 at 20:14
  • \$\begingroup\$ Ahhh, I'll give that a shot. Out of curiosity does the by string method use reflection? If so then performance would be an incentive to use the return value to stop the coroutine. \$\endgroup\$ – Douglas Gaskell Mar 28 '15 at 20:20
  • \$\begingroup\$ Yes, the string method is slower. \$\endgroup\$ – bummzack Mar 28 '15 at 21:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.