【Unity】動的なGameObjectのインスタンス化時に引数を渡す
MonoBehaviourのコンストラクタを呼ぶことができない
こんにちはYosematです。最近仕事でUnityを使い始めました。
Unityのいいところはたくさんありますが、Unityではオブジェクト指向的にコードを書くのにちょっと工夫が必要です。
僕が今回やりたかったのはずばりコレ。
MonoBehaviourから動的にMonoBehaviourがアタッチされたオブジェクトを生成する。
pythonだったら
class Hoge:
def __init__(self):
self.fuga = Fuga("fuga")
class Fuga:
def __init__(self, name: str):
self.my_name = name
みたいなコード。
using UnityEngine;
class Hoge : MonoBehaviour
{
Fuga fuga;
void start()
{
this.fuga = new("fuga");
}
}
class Fuga : MonoBehaviour
{
string myName;
void Start(string name)
{
myName = name;
}
}
とはかけません。FugaのコンストラクタはMonoBehaviourから継承しておりこちらから呼び出すことは許されません。
そもそも、UnityではMonoBehaviour自体をインスタンス化するということはありません。MonoBehaviourがアタッチされたGameObjectをインスタンス化するのです。
結論:Prefab + StaticMethodを使う
本質的にはMonoBehaviourに次のようなStaticMethodを実装するだけです。
public static MySphere Init(string message)
{
GameObject mySpherePrefab = Resources.Load<GameObject>("MySphere");
MySphere mySphere = Instantiate(mySpherePrefab).GetComponent<MySphere>();
mySphere.Message = message;
return mySphere;
}
以下詳細な手順を説明します。
項目が多い感じがしますが、細かくわけて説明しているだけで、実際には5分で終了します。
スクリプトがアタッチされたオブジェクトをPrefabとして保存
Hierarchyから適当なオブジェクトを作る
大抵の場合、アタッチしたいスクリプトによってその種類は限られます。例えば動く球体を作りたければSphereオブジェクトである必要があるでしょう。ここではSphereオブジェクトを"MySphere"という名前で生成します。
ResourcesフォルダをAssets直下に作成
続いてPrefabを保存するためのフォルダをAssets直下に作ります。フォルダ名を必ず"Resources"としなければ読まれないので注意してください。
アタッチしたいスクリプトを書く(ここがキモ)
アタッチしたいスクリプトを生成します。名前はややこしいですがMySphereとします。
自分自身がアタッチされたオブジェクトをPrefabからロードしてインスタンス化したのち、引数に応じた初期化処理を施してリターンするStaticメソッドを実装するのがキモです。
これが疑似コンストラクタとして機能します。今回はstringを受け取る疑似コンストラクタをとりつけました。
using UnityEngine;
public class MySphere : MonoBehaviour
{
public string Message { get; set; }
public static MySphere Init(string message)
{
GameObject mySpherePrefab = Resources.Load<GameObject>("MySphere");
MySphere mySphere = Instantiate(mySpherePrefab).GetComponent<MySphere>();
mySphere.Message = message;
return mySphere;
}
}
そして、先ほど作った適当なオブジェクト"MySphere"にアタッチしたいスクリプト"MySphere"をアタッチします(日本語)。
Prefabを作成する
アタッチしたらそのオブジェクトをHierarchyから先ほど作成したResourcesフォルダにドラッグ&ドロップしましょう。Prefabとして保存されます。
ここまででMonoBehaviourを初期化する際に引数を渡すコードは完成です。あとは実際に使い勝手をみてみましょう。
呼び出す
using UnityEngine;
public class Main : MonoBehaviour
{
void Start()
{
MySphere mySphere = MySphere.Init("some important message");
}
}
なんと美しい。
以上!
Discussion