- Home /
DestroyImmediate(component.gameObject) destroys component but not gameObject
I got a weird problem with the DestroyImmedeate() function. First off, here's a version of the script that I reduced to the problematic part:
using UnityEngine;
using UnityEditor;
[ExecuteInEditMode]
public class MyScript : MonoBehaviour {
public MyComponent myComponent;
void Awake() {
myComponent = Instantiate<GameObject>(
Resources.Load<GameObject>("Prefabs/MyComponentPrefab"),
this.transform
)
.GetComponent<MyComponent>();
}
void OnDestroy () {
if (EditorApplication.isPlaying)
{
Destroy(myComponent.gameObject);
}
else
{
DestroyImmediate(myComponent.gameObject); // <- this behaves wrong some times?
}
}
}
The problem occurs when I switch from edit to playmode. So basically, what I expect to happen, is that when the OnDestroy() function gets called, the GameObject attached to the myComponent variable gets removed completely.
Then, Awake() is called and a new instance is created, again, as a child in the hierarchy.
For some reason though, DestroyImmediate(myComponent.gameObject) is called but only the component gets removed. What stays is an GameObject containing all the other components that were attached to it despite MyComponent and it is still listed as a child of MyScript in the hierarchy.
If everything worked the whole GameObject should be gone so what am I missing here?
I notice your code in inside OnDestory. This is invoked when the $$anonymous$$yScript component is about to be destroyed. This means the $$anonymous$$yScript component will be removed from its game object, and possibly, that its gameobject is also being Destroyed (which would also destroy its children). I don't see why you would expect this awake function to be called again, though.
WHY this doesn't also remove the mycomponent game-object, I'm not sure. But I DO see that you don't actually check to confirm the myComponent reference is valid. I would recommend a Debug.Log(myComponent.name); or Debug.Log(myComponent.gameObject.name); command as the first step in troubleshooting
Oh I totally overlooked your comment yesterday, I'm gonna check if the reference isn't right at that point anymore, that could be it!
EDIT: Nope, the reference seems to be right when I give my manager a random name and then output it right before calling DestroyImmediate :(
According to the functions that get called, everything works as I expected after looking at the ExecutionOrder section in the docs:
I figured Awake and OnDestroy are the events that I want to use since OnEnable and OnDisable should only "pause" the managers but not remove them completely.
This is how my IDE looks when I press play:
The console output confirms that the functions are called in the right order (cleared it before pressing play). In the hierarchy you can see the "duplicate" Pooling$$anonymous$$anager with no components in the inspector. The latter is a problem because one more of these empty objects gets created everytime I press play. Even when making them hidden and putting t hem to DontSave, that's a pretty ugly "memory leak" that I can't live with
Am I missing something? Because of how you create it in Awake()
, myComponent.gameObject
is a child of the GameObject that's being destroyed when that OnDestroy()
function is called. So surely it's going to be destroyed anyway...? Explicitly destroying it in the OnDestroy()
looks superfluous to me.
It's a child in the hierarchy but the component I'm trying to destroy is not attached to the GameObject executing that code itself.
The GameObject "$$anonymous$$yScript" stays in the scene until the developer removes it but from Unitys architecture, as far as I understood it, GameObjects are getting created and deserialized or destroyed and serialized whenever an application starts or ends and therefore those functions are called even when $$anonymous$$yScript is not visibly being destroyed while switching modes.
All I really need that's not working right currently is the GameObject containing "$$anonymous$$yComponent" being destroyed before "$$anonymous$$yScript" is.
1) You're not trying to destroy a component, you're trying to destroy a gameobject (that's the whole point, right?)
2) That gameobject is instantiated as a child of the gameobject executing that code. So it will be destroyed anyway.
If you need a child to be destroyed before its parent, I'm not sure that doing it in the parent's OnDestroy makes sense, because the parent is already being destroyed at this point.
Actually you're totally right, this just led me to the solution!
So in fact, when Unity "stops", it serializes and then destroys everything so this destroy call is redundant, I could have noticed. When the application starts, the previously serialized data gets converted back into objects and additionally my custom create call is executed, that's why I'm getting two objects.
Now the reason why that component disappeared seemed to be that I set my DontSave-hideflag to the component ins$$anonymous$$d of the GameObject by accidet so the GameObject still got included into the serialization process. I should have included that in my question but I didn't expect it to have anything to do with the issue. Anyhow, with the DontSave-hideflag set to the GameObject itself, everything works and the destroy call can completely be removed (theoretically, I still want it to be there for certain reasons but that's another topic).
Long story short; my problem is solved. Thanks a lot everyone! :) Now I can't accept multiple answers unfortunately even if they all helped me but if you convert this comment, I'm accepting this one since it brought me to my final solution
"I should have included that in my question but I didn't expect it to have anything to do with the issue. "
Welcome to the club ;) glad you got it goin'.
Answer by Bunny83 · Jan 17, 2018 at 09:30 PM
You're doing some dangerous things here. ExecuteInEditMode is not ment to implement editor functionality. It's just ment to provide live feedback while in edit mode. When you enter playmode at the time the editor scene is destroyed it got already serialized. That means when the scene gets deserialized at the beginning of playmode the object will probably be recreated from the serialized data.
This line:
DestroyImmediate(myComponent.gameObject);
actually has no direct connection to myComponent since the expression myComponent.gameObject
is a gameobject reference. So it's impossible that it somehow is able to only destroy your component.
If you need some gameobjects / component at edit time you should set proper hideflags. However from the posted code it's hard to determine the purpose of the script. Where is that script even attached to?
Oh look its bunny :D thanks for helping me out again!
So this script is part of a custom terrain system I'm building and I'm using it to spawn different $$anonymous$$anagers that take care about object poolig, buffering lod changes and stuff like that. All that functionality is not interactive at all but rather constantly running in the background and I need it to run in the Editor aswell as in the playmode. Depending on which of those, I need to use a different camera and different Update loops. Thats pretty much the background and the reason why I want this object freshly initialized on every kind of startup. I dont want these $$anonymous$$anager classes to be always present, they are going to be set to HideAndDontSave when fully implemented so that only the actual Terrain component is visible if that makes any sence?
Now I think serialization is a good hint, maybe that behavior comes from that corner.. The thing I'm not getting is why is this destruction line always works and destroys the whole GameObject despite in that one situation where I need it
Actually, since this was the first answer and is just as valid as the other comments, I'm just accepting this one for now. Thanks again @Bunny83 @Glurth @Bonfire-Boy! You guys helped me a lot :)
Your answer
Follow this Question
Related Questions
How to access Custom Inspector own gameObject 1 Answer
How to add a component on a GameObject in Custom Inspector 1 Answer
Close script tab in VS, from script 0 Answers
How to create instance from model without creating a clone? 2 Answers
Change default sprite position when dragged into Hierarchy 1 Answer