- Home /
Crash when using GameObject.Instantiate
I have submitted this to Unity via Crash Report, but I'm posting here because I need an enlightenment/solution for this problem since it's very important and urgent to our project.
A public field or private with SerializeField attribute in a MonoBehaviour will make Unity crash if this field is from an abstract class and someone creates a clone of the MonoBehaviour using GameObject.Instantiate and then call a method from the abstract class, even if the field is not null.
The problem happens because Unity serialize it using the abstract type instead of the actual type.
The following example illustrate this problem, Unity will crash if you hit T:
public class CloningTests : MonoBehaviour
{
[SerializeField]
private SomethingMaker SomethingMaker;
void Start()
{
SomethingMaker = new SecondObject ();
}
void OnGUI ()
{
Event ev = Event.current;
if (ev.type == EventType.KeyUp && ev.keyCode == KeyCode.T) {
CloningTests script = (CloningTests)FindObjectOfType (typeof(CloningTests));
CloningTests clone = (CloningTests)GameObject.Instantiate (script);
clone.SomethingMaker.DoSomething ();
}
}
}
[Serializable()]
public abstract class SomethingMaker
{
public abstract void DoSomething ();
}
[Serializable()]
public class SecondObject : SomethingMaker
{
public override void DoSomething ()
{
Debug.Log ("Doing something");
}
}
Answer by Bunny83 · Aug 04, 2011 at 09:41 PM
There are several things messy / wrong:
Don't use a classname as variable name!
Your script clones itself so why are you use FindObjectOfType, "this" will do?
Your cloned Object creates a "SecondObject" in Start, but Start is called next frame so you can't access
clone.SomethingMaker
right after you instantiated it. Use Awake instead of Start. Awake is called when the instantiate is finished.I guess the crash happens because the clone also will produce another clone and so on but I'm not sure.
Besides the good will of using class inheritance your setup won't be serialized by Unity. Unity serializes by the variable type, not the actual type. If you have a variable of type
SomethingMaker
but it holds aSecondObject
, after serialization / deserialization it's just a SomethingMaker. That could also cause the crash since your base class is abstract.
I had some bad times figuring out that behaviour. The only working workaround to get those instances serialized is to make them MonoBehaviours and attach them to a GameObject. GameObject-Components are the only classes where Unity serializes the "real" type.
I'm sorry, I tried to create a simple example from my code but ended up with something not very explanatory. Your first points are right but I won't have any problem because it only clones and access Something$$anonymous$$aker after I hit a key, so that's not what is making Unity crash. Your last point is the cause, and that's what I meant when I wrote "the problem happens because Unity serialize it using the abstract type ins$$anonymous$$d of the actual type". $$anonymous$$aking the abstract class a $$anonymous$$onoBehaviour works very well, thank you very much!
The documentation says Unity will serialize all classes inheriting from UnityEngine.Object, so I tried to apply your idea using more basic classes (Object and Component), without success. Do you know if that can be achieved?
The crash actually happens because unity tries to access the abstract version of Something$$anonymous$$aker.DoSomething(), which is not a real function. If you make it virtual, it stops crashing.
Unity will also properly serialize derived classes if you derive the abstract class from ScriptableObject, this at least spares the mess of having GameObjects litterd with $$anonymous$$onoBehaviours ;)
Answer by leohotluz · Jan 27, 2019 at 09:38 PM
Same problem, I'm giving up using unity, too many bugs.