2020/11/09
というわけで、今回はUnityのInstantiate()
に関するお話です。
最近Instantiate()
のメソッドオーバーロードがたくさんあることに気付いたので、その種類と使い方をまとめてみました!
目次
公式リファレンス
以下にInstantiate()
のリファレンスが載っています。
https://docs.unity3d.com/ja/current/ScriptReference/Object.Instantiate.html
ここを見ればどのような挙動になるかほとんど書いてあるわけですが、それでは味気ないので自分で試してみました。
検証用スクリプトの作成
検証用にシンプルなスクリプトを作成します。
using UnityEngine; public class InstantiateTest : MonoBehaviour { [SerializeField] protected GameObject characterObject; [SerializeField] protected GameObject parentObject; void Start() { Instantiate(characterObject); } }
オーバーロードごとにStart()
内のInstantiate()
実行部分を書き換えて検証しました。
characterObject
にはアザラシを、parentObject
にはCubeを設定してあります。
特にアザラシとCubeであることに意味はないので、深く気にせず読み進めてくださいね。
オーバーロードごとの動作
単純に複製
複製するオブジェクトだけを指定するオーバーロードです。
Instantiate(characterObject);
生成されたオブジェクトの位置や回転・大きさは生成元のTransform
コンポーネントの値になります。
生成後に親オブジェクトを指定
複製するオブジェクトと、生成後に親オブジェクトとするオブジェクトのTransform
を指定できます。
第2引数にTransform
型を指定するとこのオーバーロードが選択されます。
Instantiate(characterObject, parentObject.transform);
生成されたオブジェクトの位置は親オブジェクトからの相対的な位置になります。
今回の例で言うと、「アザラシのXが2、CubeのXが3」の場合のアザラシのグローバル座標はXが5の地点になります。「親オブジェクト(Cube)のグローバル座標+子オブジェクト(アザラシ)のローカル座標」ですね。
「親オブジェクトを設定するけど、生成されたオブジェクトはグローバル座標の位置にしたい!」という場合のために、別のオーバーロードも用意されています。
第3引数にtrue
を指定すると、親オブジェクトを設定しつつグローバル座標そのままの位置に生成されます。
Instantiate(characterObject, parentObject.transform, true);
シチュエーションによっては親の座標を無視した位置に生成したいこともあるので、上手く使い分けましょう。
生成するオブジェクトの位置と回転を指定
オブジェクトを複製し、その生成位置と回転を指定も指定するオーバーロードです。
第2引数にVector3
型、第3引数にQuaternion
型を指定します。
Instantiate(characterObject, Vector3.zero, Quaternion.identity);
実行すると「XYZが0の位置に、XYZの回転軸が0のアザラシ」が生成されます。
おそらく最もよく使うオーバーロードではないかと思います。私もInstantiate()
を使用する際はほとんどこれを使っています。
ちなみにQuaternion.identity
は「回転していない」状態を示すものです。特に回転させなくて良い場合に使います。
https://docs.unity3d.com/ja/current/ScriptReference/Quaternion-identity.html
生成オブジェクトの位置と回転+親オブジェクトを指定
第4引数にTransform
型を指定すると親オブジェクトも設定できます。
Instantiate(characterObject, Vector3.zero, Quaternion.identity, parentObject.transform);
生成位置は親子関係を考慮せず、第2引数で指定したVector3
型のグローバル座標の位置になります。
型引数を指定する場合
これまでのInstantiate()
の5種類のオーバーロードには型引数を指定できます。5種類×型引数ありなしの2種類で合計10種類のオーバーロードが存在することになりますね。
型引数を指定すると、Instantiate()
の返り値が指定した型のインスタンスになります。例えば型引数にRigidbody
を指定すると、返り値としてそのオブジェクトのRigidbody
コンポーネントの参照を取得することができます。
型引数を指定する場合、Instantiate()
の第1引数はその型のインスタンスを指定しなければなりません。また指定したインスタンスはシーン上かプレハブでゲームオブジェクトとして存在しなければならないようです。例えば以下のようなスクリプトを実行するとNullReferenceException
が発生します。
using UnityEngine; public class InstantiateTest : MonoBehaviour { void Start() { var rb = new Rigidbody(); Instantiate<Rigidbody>(rb); } }
使いどころとしては、オブジェクト生成と共に自作したスクリプトの参照を欲しい場合とかでしょうか。
例として、以下のようにコードを書き、インスペクターからtestAzarashiObject
にTestAzarashi
コンポーネントを持ったプレハブを設定します。Instantiate()
の返り値はTestAzarashi
型になるので「GameObject
型の返り値からGetComponent()
で取得する」という手間が省けますね。
using UnityEngine; public class InstantiateTest : MonoBehaviour { [SerializeField] protected TestAzarashi testAzarashiObject; void Start() { var testAzarashi = Instantiate<TestAzarashi>(testAzarashiObject); } }
よく「シーン開始時にプレイヤーを生成し、Player
コンポーネントの参照を取得」という処理を書くので、型引数を使えば少しだけ記述を短くできそうです。
あとがき
そんなわけで、UnityのInstantiate()
の使い方についてまとめてみました!
非常によく使うメソッドなので、今後もスクリプトリファレンスには気を付けるようにします。