Question About Unity Class Hierarchy
Hello guys,
I am fairly experienced programmer and I'm aware of OOP concepts. I was reading the Unity Manual and I stumbled upon something that I can't explain, so I decided to write here. To be more specific I was reading this page:
http://docs.unity3d.com/Manual/InstantiatingPrefabs.html
This example is bothering me
// Require the rocket to be a rigidbody.
// This way we the user can not assign a prefab without rigidbody
public Rigidbody rocket;
public float speed = 10f;
void FireRocket () {
Rigidbody rocketClone = (Rigidbody) Instantiate(rocket, transform.position, transform.rotation);
rocketClone.velocity = transform.forward * speed;
// You can also acccess other components / scripts of the clone
rocketClone.GetComponent<MyRocketScript>().DoSomething();
}
// Calls the fire method when holding down ctrl or mouse
void Update () {
if (Input.GetButtonDown("Fire1")) {
FireRocket();
}
}
Here is the question. Why can we do this on a prefab that has a rigid body component? Rigidbody rocketClone = (Rigidbody) Instantiate(rocket, transform.position, transform.rotation);
The prefab is of type GameObject if I am correct. GameObject inherits from Object. The Rigidbody inherits Component. The Compoment class inhetirs from Object too.
I got really confused. Why can we cast the result from Instantiate to type of Rigidbody? Does this mean that when we attach a component (In this case Rigidbody) somekind of inheritance is happening behind the scenes? How does things work behind the scenes? I am somewhat tired and I might not be thinking straight and my question might be silly, but It really got my attention and I want to know how it works.
Regards
It does not inherit from gameobject, i think its just a built in conversion method to make it easy to use. To be honest i never used this because of the reasons you described.
Ins$$anonymous$$d of ThankYou comments, it's better to use the +1 button (and not write anything.) The purpose of UA is to get searchable answers for others. ThanksYous make it harder for them.
The prefab, on line 3, is a Rigidbody, so it's Rigidbodies all the way. The trick is, Instantiate returns a pointer to the copy of the part you gave it.
Instantiate uses the Rigidbody pointer you give it to find and copy the entire gameObject. But then it returns a pointer to just the Rigidbody it made. As you note, RBs inherit from Objects, so it returns an Object pointer, but it's really a pointer to the RB. (Rigidbody) dynamically casts it back.
You don't have to do that with gameObjects because Unity write an implicit cast for you.
Thank you. I will exa$$anonymous$$e things carefully again, but thanks to you guys it's clearer to me now.
I just noticed that rocket example is out of date. The (Rigidbody) cast doesn't need to be there anymore. It just returns a Rigidbody.
Instantiate now uses a template (the angle-bracket trick) to always return the type you gave it. Try Instantiate(someRigidbody), look at the tool tip, and you'll see. Not sure which version it was changed in.
Answer by Bunny83 · Aug 21, 2016 at 03:13 PM
This is actually a huge feature of Unity's component system. Instantiate can actually clone any UnityEngine.Object. So you pass in a source object and get back a clone of it. This works with Meshes, Materials, Textures, and so on. There is a special case when instantiating components. Since Components can't live on their own (they always need to be attached to a GameObject) when you instantate a Component, the gameobject it contains is also cloned. And when you clone a gameobject all components on that gameobject will be cloned as well. Furthermore, since the Transform component is also cloned, it will also clone all child transforms as well as their gameobjects..
Keep in mind that the actual hierarchy is build by the transform components, not the actual gameobjects. GameObjects are just empty containers.
In most cases you want to make use of this feature. Instantiate will always return the same type that you passed in. So If you pass in a reference to a MonoBehaviour script which is on a prefab, the whole prefab will be instantiated and you get direct access to that script on the newly instantiated object. This saves you a GetComponent call. So whenever you declare a variable to hold a prefab reference, don't use "GameObject" since it's the most useless class. If you don't have any scripts on the prefab, use Transform.
Also keep in mind that the Component class itself also has all the GetComponent methods so you can directly get another component from a component reference.
edit
Just to clear up some confusion. This won't work:
public GameObject prefab;
Transform inst = (Transform)Instantiate(prefab);
This will throw an invalid casting exception since you instantiated a gameobject reference which you can't cast to Transform. However this does work:
public YourMonoBehaviourClass prefab;
YourMonoBehaviourClass inst = (YourMonoBehaviourClass)Instantiate(prefab);;
Again, Instantiate returns the exact same type you passed in. You can only assign prefabs / gameobjects to the prefab variable that have a "YourMonoBehaviourClass" component attached. When dragging the object onto the object field in the inspector you don't assign a GameObject reference but a reference to the "YourMonoBehaviourClass" instance on that gameobject.
Thank you very much for spending time answering me. Your help is much appreciated. I believe that such details about how things work are very important.
Answer by off99555 · Aug 21, 2016 at 04:18 PM
Your rocket is a GameObject. That's right. What happens is just a trick from Unity. Normally, you would paste a Rigidbody component into rocket variable for it to work. But when you paste a GameObject instance into it, it will just search for the first detected Rigidbody component inside that GameObject to use in the script.
The rocket itself is not a Rigidbody. But it has a component Rigidbody at least once. If you attach 2 Rigidbody components to the rocket then Unity will just select one component from those.
Answer by Skylander17 · Aug 21, 2016 at 02:40 PM
I think, they wrote that code for variety. In normal situation, Instantiate method clone a prefab to scene. I think, they need rigidbody of a gameobject for this example. Here is Instantiate method:
https://docs.unity3d.com/ScriptReference/Object.Instantiate.html If you read this reference, you can also find how to Instantiate clone script instances directly from a prefab.
Your answer
Follow this Question
Related Questions
Update instatiate doesn't work? 1 Answer
How can I instantiate a object on the world coordinates 1 Answer
Instantiate prefab if no prefab exists at location 1 Answer
Instantiated Object Has Wrong Rotation 0 Answers
Instantiate object (on touch position) by touch on the collider of other object 1 Answer