Do not know how to use coroutines in Unity3D

Question

In Unity3D, this is my code:

void ActivateBuff1(){
    gun.equippedGun.msPerShot /= 2;
    gun.equippedGun.shotsLeftInMag += 10;
    StartCoroutine (WaitRage ());
}

void ActivateBuff2(){
    player.speedModifier *= 1.5f;
    StartCoroutine (WaitSpeed ());
}

IEnumerator WaitRage(){
    yield return new WaitForSeconds(powerUpDuration);
    gun.equippedGun.msPerShot *= 2;
}

IEnumerator WaitSpeed(){
    yield return new WaitForSeconds(powerUpDuration);
    player.speedModifier /= 1.5f;
}

Everytime a player run into a power up one of the ActivateBuff Methods gets called. Obviously powerUps effects don't last forever though so I used IEnumerators to reverse the effects of my original method after the wait for a certain number of seconds. For some reason though, the code within the IEnumerators never gets called. Please help...(and please suggest an alternative way of coding this perhaps as I know it isn't very clean)


Show source
| c#   | unity3d   2016-11-24 19:11 2 Answers

Answers ( 2 )

  1. 2016-11-24 20:11

    Under normal circumstances, the code you've supplied should work fine. However, as determined in the comments, there's a caveat - if the Gameobject calling the coroutine is disabled/destroyed before the delay from WaitForSeconds() has completed, the coroutine will be stopped and the remaining code won't be called at all. You will either need to wait for the coroutine to finish before destroying the Gameobject, or have some other Gameobject call the coroutine.

    You mentioned that you were also looking for alternatives that might simplify your code - you might consider Invoke(), which lets you call a method after a specified delay. (As long as you're not triggering this very often, the overhead from reflection won't have an appreciable effect on your performance.) So your code could be rewritten to be somewhat shorter:

    void ActivateBuff1(){
        gun.equippedGun.msPerShot /= 2;
        gun.equippedGun.shotsLeftInMag += 10;
        Invoke("ResetPlayerRage", powerUpDuration);
    }
    
    void ActivateBuff2(){
        player.speedModifier *= 1.5f;
        Invoke("ResetPlayerSpeed", powerUpDuration);
    }
    
    void ResetPlayerRage(){
        gun.equippedGun.msPerShot *= 2;
    }
    
    void ResetPlayerSpeed(){
        player.speedModifier /= 1.5f;
    }
    

    Unfortunately, Invoke() will also be cancelled if the Gameobject is destroyed - but unlike a coroutine, it won't be cancelled if the Gameobject is disabled. So you could disable the Gameobject first (so it becomes invisible and doesn't interact with anything), then destroy it only after running the delayed method:

    void ActivateBuff1(){
        gun.equippedGun.msPerShot /= 2;
        gun.equippedGun.shotsLeftInMag += 10;
        gameObject.SetActive(false);
        Invoke("ResetPlayerRage", powerUpDuration);
    }
    
    void ResetPlayerRage(){
        gun.equippedGun.msPerShot *= 2;
        Destroy(gameObject);
    }
    

    Here's a summary of whether Invoke() and coroutines will be stopped depending on how you manipulate the script component or entire Gameobject:

    ..........................................................................
    :                                  :                     :               :
    :          Does it stop?           :   InvokeRepeating   :   Coroutine   :
    :                                  :                     :               :
    :..................................:.....................:...............:
    :                                  :                     :               :
    :   Disable the script component   :         No          :      No       :
    :                                  :                     :               :
    :..................................:.....................:...............:
    :                                  :                     :               :
    :   Destroy the script component   :         Yes         :      Yes      :
    :                                  :                     :               :
    :..................................:.....................:...............:
    :                                  :                     :               :
    :   Disable the game object        :         No          :      Yes      :
    :                                  :                     :               :
    :..................................:.....................:...............:
    :                                  :                     :               :
    :   Destroy the game object        :         Yes         :      Yes      :
    :                                  :                     :               :
    :..................................:.....................:...............:
    
  2. 2016-12-02 03:12

    Man, Serlite said everything.. However I would have dealt with this kind of situation differently.

    If I got it right, you setted this ActivateBuff function in the script attached to some kind of item that sets a modifier in the equipped gun and afterwards gets disabled. Instead of doing that, I would just create a Buff function in the equipped gun script(passing the modifier and the time as params) and let the gun itself to handle this.

    Since the equipped gun won't disappear, it would solve your problem and ideally could even be a more generic solution. Once you could pass through another power up which could lately generate some unexpected behavior(because there would be many scripts buffing and unbuffing the gun).

◀ Go back