🕌

【Unity】動的なGameObjectのインスタンス化時に引数を渡す

2022/10/11に公開

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