Search Unity

Coroutine from another script - null exception

Discussion in 'Scripting' started by Nixaan, Dec 1, 2015.

  1. Nixaan

    Nixaan

    Joined:
    May 30, 2013
    Posts:
    118
    Hi,
    I'm getting strange null exception error when i try to run coroutine from another script.
    The setup is next:
    I have state machine based on objects (each state is different class inheriting IState interface, NON MonoBehavior). Apart from states there is one main state looper (MonoBehavior attached to the object it controls) that executes currentState.UpdateState() method on every frame. currentState (inside the looper) is public variable that points to the active state. Each state can change to what state currentState variable points (this is how states are changed from one to another - current active state changes currentState variable to point to another state, then the next frame state looper continues to loop but different state).

    Below is the coroutine that i want to run and a method that fires it.
    I tried 2 options - 1: Placing them inside the MonoBehavior state lopper or 2: Placing them inside a state and making that state inherit MonoBehavior on top of implementing IState interface. The code below is how it looks if it is inside the state looper.


    Code (CSharp):
    1.  
    2. public void UsedByBeingHitState()
    3. {
    4.     StartCoroutine(PostEffectsOfBeingHit());
    5. }
    6.  
    7. // The coroutine makes a character unhittable and its sprite to blink on and off for few secs after being hit
    8. public IEnumerator PostEffectsOfBeingHit()
    9. {
    10.     triggerCollider.enabled = false; //oFSM.triggerCollider.enabled if inside state
    11.     float loopTime = 0;
    12.     while (loopTime < 2.2f) {
    13.         sprite.enabled = !sprite.enabled; //oFSM.sprite.enabled if inside state
    14.         float blinkSpeed = sprite.enabled ? 0.15f : 0.075f; //oFSM.sprite.enabled if inside state
    15.         loopTime += blinkSpeed;
    16.         yield return new WaitForSeconds(blinkSpeed);
    17.     }
    18.     sprite.enabled = true; //oFSM.sprite.enabled if inside state
    19.     yield return new WaitForSeconds(0.6f);
    20.     triggerCollider.enabled = true; //oFSM.triggerCollider.enabled if inside state
    21. }
    22. // oFSM points to the state looper
    23.  
    Now the actual problem: the coroutine works only if from the state is called oFSM.UsedByBeingHitState() method which then calls the coroutine (i.e. both the method and coroutine are inside the looper).

    An error is returned if I try some of the next:
    1. Call UsedByBeingHitState() inside a state, and the method then calls the coroutine inside the looper with StartCoroutine(oFSM.PostEffectsOfBeingHit()) (i.e. method inside state, coroutine inside looper)
    2. Call UsedByBeingHitState() inside a state, and the method then calls the coroutine inside the state too (i.e both are inside the state and state inherits MonoBehavior and implements IState interface)
    3. Call the coroutine directly with StartCoroutine(oFSM.PostEffectsOfBeingHit()) or StartCoroutine(PostEffectsOfBeingHit()) (i.e. calling the coroutine no matter if inside the state or looper)


    The error I get in all the cases is:
    Is there any way to avoid that error and place the coroutine inside the state?
     
    Last edited: Dec 1, 2015
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    If you are in Script A and start a coroutine located in Script B, the coroutine is run in Script A's Monobehaviour context.

    However, obviously all instance variable references are in Script B. This can get a bit confusing. It is even more confusing if you have the same scripts on two different game objects and they are starting coroutines in the other one.

    I suggest putting in debug log output that displays the .name field of the script so you can see which one is actually doing the crashing, as well as using the debugger to find out precisely what variable is null.
     
  3. Nixaan

    Nixaan

    Joined:
    May 30, 2013
    Posts:
    118
    I found the problem.
    The states are not MonoBehaviors so they are not attached to the game object. The state with the coroutine (even after changing it to inheriting MonoBehavior) was still not attached and this probably caused the error because now after attaching it works.