A question about Instantiate

I was following the ‘Scripting’ video Tutorials (great job by the way :)), and could not wrap my head around the Instantiate method usage (I cross-checked the documentation, and it confirms what has been shown in the video).
Both the video and the documentation use the ‘as’ operator to cast the object instance returned by Instantiate to a RigidBody instance.
I understand that casting to a RigidBody instance allows the code to access the properties and methods pertaining to such class (for example, the velocity property).
What I don’t understand is: how can a GameObject instance (for example the projectile in the video tutorial) be cast to a RigidBody instance ?
In other words, what is the relationship between a GameObject and its RigidBody component ?
I always cast ‘along’ an inheritance scheme, but the GameObject/Component seems more like a ‘has a’ relationship rather than a ‘is a’ one.
Any help, appreciated!

You have some misunderstanding here. You can’t cast between a component and a game object.

Instantiate is a slightly strange method in that no matter what you send it returns a object. The object is the same type as the object passed in as the first argument. But you have to cast it to do anything useful. (Note to any Unity devs, a generic version of Instantiate would be nice!).

Here are some code examples

// This will return a GameObject
GameObject myPrefab;
GameObject clone =(GameObject) Instantiate (myPrefab);

// This will return a RigidBody
RididBogy myPrefabRigidBody;
RigidBody clone = (RigidBody) Instantiate (myPrefabRigidBody);

// This will not work, casting a RigidBody to a GameObject
RigidBody myPrefabRigidBody;
GameObject clone = (GameObject) Instantiate (myRigidBodyPrefab);
2 Likes

Many thanks BoredMormon !
I might add that, reviewing the video about the Instantiate method (http://unity3d.com/learn/tutorials/modules/beginner/scripting/instantiate) at 1:44, I noticed that the references passed to the public instances declared by the UsingInstantiate script, are not simply Rocket and RocketPlace, but Rocket (RigidBody) and RocketPlace (Transform): this way the editor seems to infer which Component of the GameObject is compatible with the type required by the script.

It helps to imagine the “as” keyword to mean “promote” or “demote” rather than “cast”

Casting requires explicit or implicit methods to covert one type to another.

Promoting / Demoting allows you to change the runtime type of an object to one of it’s base or derived classes.

In the case of Instantiate, it returns a UnityEngine.Object, which is the base class for all objects unity works with.

Now, you cant cast a gameObject to a rigidBody, but FROM UnityEngine.Object, you can “promote” to either.

Edit: code example because the syntax I was thinking is different from BoredMormon

//Promote
var rigidBody = Instantiate(prefab) as RigidBody;

//Demote
var obj = rigidBody as UnityEngine.Object;

//unsupported cast, returns null
var gameObject = rigidBody as GameObject;
1 Like

Since we are on the topic of casting, the key difference between casting as I showed it and casting as @BenZed showed it is the response to impossible casts. My version will fail with an error as soon as the cast is attempted (unsafe). Using the as key word will return null if the casting is not possible, hence using as is referred to as ‘safe’ casting.

There are advantages and disadvantages to both. Unsafe casting is slightly faster. Safe casting is better if you are not totally sure if the cast can be done.

Note all of this applies to C#. JavaScript behaves differently.

1 Like

Just to add on to the discussion about the casts:

You should almost always use the (type) style casts because almost all of the time you know the exact type it should be and it should be an error if it is a different type. e.g. with Instantiate you know exactly what type you put in and gets returned so you should use an (type) cast. The reason for this is that you will want an error as soon as possible. With an “as” cast it will return null and you will either need to explicitly check for that or end up with a null reference exception at a later point. But with a () cast you will get an exception the moment the casting fails.

The “as type” cast is only useful when you are not sure about the actual type. In other languages you would first do a type check before casting which will do a type cast/check twice(once when checking and once when casting), but with “as type” it only needs to do the check/cast once.

e.g.

if (obj is Type) // <-- typecheck here
{
    Type t = (Type)obj; // <-- typecheck here
}

vs

Type t = obj as Type; // <-- typecheck here
if (t != null)
{
}
3 Likes

There you go! I’ve been doing it inefficiently, all this time!

Thats a practice i’m going to adopt.

Fail fast is definely a good reason for () casting. If there is a problem with your code it’s nice to know about it early.