Coroutine stopped working.

Hey all. I added a NavMesh to my game and for some reason a couple of coroutines from one of my scripts stopped working. I have no idea why. I didn’t touch the script nor the object it’s attached to. Even when I cleared the NavMesh, the coroutines still didn’t work.

In a nutshell, the object drops when the player hits a trigger on the floor, killing the player. The object then resets its position after a few seconds. The trap drops just fine, but then just stays there. Nothing in the coroutines is run. Here are the relevant scripts:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TrapDrop : MonoBehaviour {

    Vector3 spawnPoint;
    Rigidbody rb;
    public Vector3 drop;
    MeshRenderer meshRenderer;
    PlayerMovement playerMovement;
   
    void Start ()
    {
        rb = GetComponent<Rigidbody>();
        drop = new Vector3(0, -800 , 0);
        spawnPoint = transform.position;
        meshRenderer = GetComponent<MeshRenderer>();
        playerMovement = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerMovement>();
    }
   
        private void OnCollisionEnter(Collision collision)
    {
        if (collision.collider.tag == "Player")
        {

            StartCoroutine(WaitTwo());
            StartCoroutine(Wait());
        }
     }

    public IEnumerator WaitTwo()
    {
        if(playerMovement.isDead)
        {
            yield return new WaitForSeconds(1);
            meshRenderer.enabled = false;
        }
    }

       public IEnumerator Wait()
    {
        if (playerMovement.isDead)
        {
            yield return new WaitForSeconds(2);
            transform.position = spawnPoint;
            rb.isKinematic = true;
            meshRenderer.enabled = true;

        }
    }

}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMovement : MonoBehaviour {
   
    public float moveSpeed;
    float maxSpeed = 5;
    Rigidbody rb;
    Vector3 input;
    public Vector3 spawnPoint;
    public GameObject deathParticles;
    MeshRenderer meshRenderer;
    Enemy enemy;
  
   
    public bool isDead = false;
    public bool enemyTrigger = false;


    void Start ()
    {
        rb = GetComponent<Rigidbody>();
        spawnPoint = transform.position;
        meshRenderer = GetComponent<MeshRenderer>();
        enemy = GameObject.FindGameObjectWithTag("Enemy").GetComponent<Enemy>();
    }

  
   
    void FixedUpdate ()
    {
        input = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));

      
         if(rb.velocity.magnitude < maxSpeed)
        {
            rb.AddForce(input * moveSpeed, ForceMode.Acceleration);
        }

        FallDeath();

    }
    private void OnTriggerEnter(Collider other)
    {
        if (other.tag == "Enemy")
        {
            Die();
        }
        if (other.tag == "EnemyTrigger")
        {
            enemyTrigger = true;
           
        }

    }

    private void OnCollisionEnter(Collision collision)
    {
        if(collision.collider.tag == "Trap")
        {
            Die();
        }
    }

   

    public void Die()
    {
        Instantiate(deathParticles, transform.position, Quaternion.identity);
        meshRenderer.enabled = false;
        rb.isKinematic = true;
        isDead = true;
        transform.position = spawnPoint;
        enemyTrigger = false;
       
        enemy.enemyMesh.enabled = false;
        StartCoroutine (Wait());
     


    }

    void FallDeath()
    {
        if (transform.position.y <= 0.9f)
        {
            Die();
        }
    }

    public IEnumerator Wait()
    {
        if (isDead)
        {
            yield return new WaitForSeconds(2);

           
            rb.isKinematic = false;
            isDead = false;
            meshRenderer.enabled = true;
            enemy.enemyMesh.enabled = true;

        }
    }

}

Can you see anything in the above scripts that might be causing the problem?

Well hello again,

so what does the ‘drop’ variable do? I never see it used.
It’s kinda funny that your WaitTwo waits 1 second, and your Wait waits 2 seconds haha. :slight_smile:

Have you debugged the collision? Is it being called on either the player or the trap?
Do you get any debug log statements there, above even the tag check…?

Hey again.

The drop is called in another script for the object that triggers the drop (I’m not the most efficient coder yet!). That works fine. The trap drops. All the other objects reset their positions when the player dies, but the trap just stays put.

I think the collision is being called on both. In the player script, it executes the Die() function. In the TrapDrop script, it executes the coroutines. It all worked before I created a NavMesh.

I’m embarrassed to say I don’t know how to go about debugging.

Nothing comes up on the console, if that’s what you mean. Besides the message about inconsistent line endings, which is something I always get.

Ah okay. So, yes I meant in the console.

You just wrote that it executes the coroutines, but how do you know that? From Debug.Log?
I wonder if it’s possible that this script gets the collision message first, and that means the player “isDead” is not true, at the time it goes to the coroutine.

You could try:

yield return new WaitForEndOfFrame();

Put that just above the check for is the player is dead in your trap drop coroutines (or at least 1 to check).

The only reason I know it runs (or used to run them, at least) the coroutines is because it did it fine before. However, it doesn’t do it any more. I checked settings on the inspector to see if any lines code were being executed, but none are.

That line didn’t work, unfortunately. I also tried increasing the Wait Coroutine in the Player Movement script, to make sure isDead was true for longer. Didn’t work.

Okay, so you were only sure it was before, but not now. That was a little confusing.
If that’s the case, then I’d try this for starters:

print("Got collision"); // first line in OnCollisionEnter

let me know if you see the message in the console.

Yep. That worked. Messaged displayed.

Problem with the isDead bool, then?

That would be my guess. Can you please paste the code you tried from my previous suggestion (not the print statement, but the end of frame yield).?

I added:

if (playerMovement.isDead)

{          
print("Got collision");
}

To the first line of the collision. Message didn’t print.

Sure.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TrapDrop : MonoBehaviour {

    Vector3 spawnPoint;
    Rigidbody rb;
    public Vector3 drop;
    MeshRenderer meshRenderer;
    PlayerMovement playerMovement;
  
    void Start ()
    {
        rb = GetComponent<Rigidbody>();
        drop = new Vector3(0, -800 , 0);
        spawnPoint = transform.position;
        meshRenderer = GetComponent<MeshRenderer>();
        playerMovement = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerMovement>();
    }
  
        private void OnCollisionEnter(Collision collision)
    {
        if (collision.collider.tag == "Player")
        {
            if (playerMovement.isDead)

            { print("Got collision"); }
            StartCoroutine(WaitTwo());
            StartCoroutine(Wait());
            rb.isKinematic = true;

        }
     }

    public IEnumerator WaitTwo()
    {
        if(playerMovement.isDead == true)
        {
            yield return new WaitForEndOfFrame();
            meshRenderer.enabled = false;
          
        }
    }

       public IEnumerator Wait()
    {
        if (playerMovement.isDead == true)
        {
            yield return new WaitForEndOfFrame();
            transform.position = spawnPoint;
          
            meshRenderer.enabled = true;

        }
    }

}

Okay, cool… I was just curious if you could paste the code I suggested, like just to make sure it’s in the right spot? :slight_smile:

Ahh okay, and that is not where I meant, okay. :slight_smile:
So, remove the isDead from the collision area…
then re-write the coroutines like so (I’ll just do 1 to show you):

public IEnumerator WaitTwo()
{
   yield return new WaitForEndOfFrame();
   if(playerMovement.isDead == true)
   {
        yield return new WaitForSeconds(1);
        meshRenderer.enabled = false;     
   }
}

Try that :wink:

My bad. Sorry about that.

That… worked haha. Oh god, don’t tell me I just had my WaitForSeconds in the wrong spot?

No, I wouldn’t say so necessarily, about your waitfor seconds. Because that sounds like you want to wait to do other stuff (not check if the player is dead).
What happened is that the trap got the collision message first, before the player, so the player didn’t know it was dead, yet. Now, the trap is checking “hey, is the player dead”, but their script is running later in the same frame, and it reports “no”. Yielding until the end of the frame lets you wait out the rest of the scripts to run…

All this being said, and it’s good it’s working. If it were me, and I had a trap that was going to kill the player. Maybe what I would do , instead, is check if I’ve hit the player, then I’d check if they’re dead (similar to you), and if they’re not dead, I’d kill them myself lol Maybe make the trap being the killer. Rather than the player dying. Not really sure one way is better than the other, however in my example you would be sure of that at the time…

Anyways… Glad it’s resolved :slight_smile:

You’re an absolute gem, sir. Thanks for all the help. Can’t tell you how much I appreciate it.

The same thing from last night is bugging me, though. Both of those problems didn’t exist before the NavMesh was created. That is to say, those mechanics worked fine with those lines of code. No idea why they suddenly stopped working.

Sure, well don’t feel too spooked about it. Sometimes, when you compare a Vector3 for equality, you can get lucky and it will equate to true. As I was telling you yesterday, though, it’s better to always do a “close to” check, instead, because that will always work. Remembering and practicing that will ensure you don’t get caught in bad spots :wink:
As for why this might have worked before, it’s possible that you added scripts, or moved something around in the game (to be honest, I’m not sure how Unity decides which scripts go first). Perhaps, in physics, it’s just a coincidence which one gets it, perhaps there are rules, perhaps it’s related to Unity scripts’ order… so on , so on… beyond my knowledge/scope of this question :slight_smile: But essentially, you were “lucky” it worked before, too :wink: 50/50 lol
Now, it will always work, like the position check, too.

1 Like

Oh, and you’re welcome for the help. No problem. :slight_smile: Enjoy making your game!

1 Like