Can I check if this.gameObject was destroyed?
Here's a simple version of a coroutine that's running on one of my objects:
public IEnumerator PulseOnGround()
{
while (gameObject.activeInHierarchy)
{
//do stuff
yield return new WaitForFixedUpdate();
if (gameObject == null) yield break;
}
}
This throws a MissingReferenceException when the object is destroyed from another script. It appears that the script keeps running after it's destroyed, but I can't find a way to check if the gameObject still exists from within the script.
Is it possible to break this coroutine on destroy from within this script, without using StopCoroutine? Or do I need another script to keep track of whether this script is still alive and call StopCoroutine on any coroutines that might still be running?
I'm trying to do this without StopCoroutine because I don't have references to every coroutine that's running, and I would want all of them to stop on destroy anyway.
Answer by ArturoSR · Aug 01, 2016 at 01:10 AM
Hi, may be you need to check it by a different way, when you use a component to check if his game object is still alive, this always drops a Null Reference Exception because the method still works on memory until finished his job, that's why you get that warning; the better way doing this is if the tracker of that object check it, not the object it self.
Thanks. So, to clarify, the only way to check if an object was destroyed is from outside the object?
You can also use OnDestroy() which is called when the object is destroyed.
https://docs.unity3d.com/ScriptReference/$$anonymous$$onoBehaviour.OnDestroy.html
Didn't test this example, but I think it should work:
private Coroutine pulseOnGroundRoutine;
private void Start()
{
pulseOnGroundRoutine = StartCoroutine(PulseOnGround());
}
public IEnumerator PulseOnGround()
{
while (gameObject.activeInHierarchy)
{
//do stuff
yield return new WaitForFixedUpdate();
}
}
private void OnDestroy()
{
StopCoroutine(pulseOnGroundRoutine);
}
Answer by bilalakil · Jul 20, 2020 at 07:51 AM
I added a helper extension for this:
using System;
using UnityEngine;
public static class Helpers {
public static bool IsValid(this MonoBehaviour comp) {
try {
if (comp.gameObject == null) return false;
} catch(Exception) {
return false;
}
return true;
}
}
Now in my MonoBehaviour
s I can just check that and abort:
if (!this.IsValid()) return;
Answer by suribe · Sep 21, 2016 at 03:15 PM
This might be a little old, but have you tried changing your loop to:
public IEnumerator PulseOnGround()
{
while (gameObject != null && gameObject.activeInHierarchy)
{
//do stuff
yield return new WaitForFixedUpdate();
}
}
In this way you avoid the exception from gameObject.activeInHierarchy
sorry, something went really bad after saving the answer and the code was wrecked. Fixed it.
meaning: wile "This" GameObject is Not null & it is also active in hierarchy, then to wait for a fixed update. where is say's "do stuff" could have 1 debug log to see if its getting to that point over and over again in the console for as long as the Coroutine is running and again another after the wait for fixed update and see when its getting there, and you can also put one in the OnDestroy unity method to see if it gets to that point last. shouldn't cause any errors and you can see whats happening. I make a small debug checker and setter as a helper when developing, I do this a lot but i always have private variable named debug$$anonymous$$ode, in all my scripts except my $$anonymous$$ain game manager. There it is a public variable so i can set it in the inspector in 1 location in my project. When i do debug logs anywhere in my code, first thing i put is if(debug$$anonymous$$ode) above it and it will only log if debug$$anonymous$$ode is true. There is a return method that gets the variable from PlayerPrefs as it's not a variable detrimental to the game if tampered with. I do this via a int and converts back to bool 1 being true, 0 being false, $$anonymous$$y $$anonymous$$ainGame$$anonymous$$anager always has a void SetDebug$$anonymous$$ode() method and set it on it's Awake so All other scripts will be in debug mode at the same time as the main game manager. very easy code to use and setup, it's a very useful toolet.
EG:
Other scripts bool GetDebug$$anonymous$$ode() { int message=PlayerPrefs.GetInt("Debug$$anonymous$$ode",1); if(message==1){ debug$$anonymous$$ode =true; return debug$$anonymous$$ode }else{ debug$$anonymous$$ode =false; return debug$$anonymous$$ode } }
void Update(){ if(debug$$anonymous$$ode){ Debug.Log("Log A $$anonymous$$essage"); } }
$$anonymous$$G$$anonymous$$ void Awake(){ SetDebug$$anonymous$$ode(); }
$$anonymous$$G$$anonymous$$ void SetDebug$$anonymous$$ode() { PlayerPrefs.SetInt("Debug$$anonymous$$ode",1); }
Answer by animal531 · Feb 23, 2021 at 03:21 PM
When the GO is destroyed the updates on it's child MonoBehaviours might still run for a frame.
I find adding a check at the top of the MonoBehaviour's Update method such as
if (this == null) return;
is sufficient.
Answer by Matt_Gamer · Feb 09, 2019 at 01:15 PM
On most of my games in which the player could die I don't destroy the gameobject, but I just Deactivate it by using: gameObject.SetActive(false);
. You could also create a GameObject variable of an object that the script component isn't on, assign it, and do NameOfObject.SetActive(false);
. You could put NameOfObject.gameObject.SetActive(false);
if it doesen't work but it likely will.
Your answer
Follow this Question
Related Questions
If you want to destroy the game object, please call 'Destroy' on the game object instead. 1 Answer
Coroutines WaitForSeconds question... 3 Answers
Make an object move from Point A to Point B then back to Point A, and then destroy itself 1 Answer
Keep GameObject destroyed on returning to the scene 1 Answer