Trouble with CoRoutines and SetActive

Hello again…! :smile:

First off, I just want to thank all of you in this community for answering my questions and helping me out. I am trying to learn C# and I have plans about joining real life courses to become a better programmer. I have already learned a lot thanks to all of you.

Now on to my question of the hour :stuck_out_tongue:

I am having troubles making this script work. What I want to happen is this:
When a bullet from my gun hits an object with the tag, I want the gameObject to be de-activated and wait 5 seconds. After the 5 seconds I want the mesh renderer of that object to blink for a second or two and then re-enable the game object. Here’s what I’ve got:

using UnityEngine;
using System.Collections;

public class RemovableObject : MonoBehaviour {
    IEnumerator OnCollisionEnter (Collision col)
    {
        if(col.gameObject.tag == "RemovableObject")
        {
            col.gameObject.SetActive (false);
            yield return new WaitForSeconds (5);
            yield return StartCoroutine(DoBlinks(2f, 0.2f));
            col.gameObject.SetActive (true);
        }
    }
    IEnumerator DoBlinks(float duration, float blinkTime)
    {
        while (duration > 0f)
        {
            duration -= Time.deltaTime;

            //toggle renderer
            GetComponent<Renderer>().enabled = !GetComponent<Renderer>().enabled;

            //wait for a bit
            yield return new WaitForSeconds(blinkTime);
        }

        //make sure renderer is enabled when we exit
        GetComponent<Renderer>().enabled = true;
    }
}

This script is attached to my bullet prefab. The removable objects are tagged “RemovableObject”.

What happens right now is that the object gets de-activated and waits for 5 seconds but then the BULLET starts blinking and not the Object thats been hit. after the bullet is done blinking, the object is activated again.

So how can I make the object blink and not the bullet? I tried putting col.GetComponent<Renderer>().enabled = !GetComponent<Renderer>().enabled; on line 22, but that returned an error…

Cheers guys.

It’s because on line 22 you call ‘GetComponent()’.

When you do this, really you’re calling a instance method on ‘this’ scoped to where the function is.

Because this script is on the Bullet, it’s getting the Renderer on the Bullet.

What you should be doing is passing the GameObject from the Collision into the ‘DoBlinks’ routine and calling ‘GetComponent’ on that:

using UnityEngine;
using System.Collections;

public class RemovableObject : MonoBehaviour {
    IEnumerator OnCollisionEnter (Collision col)
    {
        if(col.gameObject.tag == "RemovableObject")
        {
            col.gameObject.SetActive (false);
            yield return new WaitForSeconds (5);
         
            var rend = col.gameObject.GetComponent<Renderer>();
            if(rend != null)
            {
                yield return StartCoroutine(DoBlinks(rend, 2f, 0.2f));
            }
            col.gameObject.SetActive (true);
        }
    }
    IEnumerator DoBlinks(Renderer rend, float duration, float blinkTime)
    {
        while (duration > 0f)
        {
            duration -= Time.deltaTime;

            //toggle renderer
            rend.enabled = !GetComponent<Renderer>().enabled;

            //wait for a bit
            yield return new WaitForSeconds(blinkTime);
        }

        //make sure renderer is enabled when we exit
        rend.enabled = true;
    }
}

Although I see a critical problem here… the target has been deactivated. So the renderer isn’t even rendering. Probably want to SetActive(true) before calling DoBlinks.

I cant activate the gameObject before the blinking. The collider needs to be turned off until the blinking is complete.

Ok, so I used my original script, but I put it on the objects I want to be removed in stead.

using UnityEngine;
using System.Collections;

public class ObjectBlinker : MonoBehaviour {
    IEnumerator OnCollisionEnter (Collision col)
    {
        if(col.gameObject.tag == "Bullet")
        {
            this.gameObject.SetActive (false);
            yield return new WaitForSeconds (6);
            this.gameObject.SetActive (true);
            yield return StartCoroutine(DoBlinks(0.1f, 0.1f));
            this.gameObject.SetActive (true);
        }
    }
    IEnumerator DoBlinks(float duration, float blinkTime)
    {
        while (duration > 0f)
        {
            duration -= Time.deltaTime;

            //toggle renderer
            GetComponent<Renderer>().enabled = !GetComponent<Renderer>().enabled;

            //wait for a bit
            yield return new WaitForSeconds(blinkTime);
        }

        //make sure renderer is enabled when we exit
        GetComponent<Renderer>().enabled = true;
    }
}

This works but as mentioned above, I need the mesh collider to be deactivated until the blinking is complete.

So I’m guessing the collider and the renderer are on different GameObjects.

In which case, deactivate the collider, and get the related target GameObject that has the renderer.

In the end, whatever way you go, you need to consider the scope of where the script is attached, and what you’re calling ‘GetComponent’ on.

Well, the collider is on the same GameObject so tell me if im doing something right here:

IEnumerator OnCollisionEnter (Collision col)
    {
        if(col.gameObject.tag == "Bullet")
        {
            this.gameObject.SetActive (false);
            yield return new WaitForSeconds (6);
            this.gameObject.SetActive (true);
            this.GetComponent<BoxCollider> ().enabled = !GetComponent<BoxCollider> ().enabled;
            yield return StartCoroutine(DoBlinks(0.1f, 0.1f));
            this.gameObject.SetActive (true);
            this.GetComponent<BoxCollider> ().enabled = GetComponent<BoxCollider> ().enabled;

Now the BoxCollider is being deactivated, but not enabled again.

I think disabling GameObject stops the ticking of coroutines. After “this.gameObject.SetActive(false)” the method will never execute pass the “yield return”.

I believe it’s safe to say that YoloJoe resolved the issue in the four years since he posted that…