前回の記事で、動的な引数をつけてUnityEventを使い方法を紹介しました。
ただそれには1つ問題がありまして、それはオブジェクトをプレハブ化するとUnityEventに割り当てていたオブジェクトが外れてしまうという点です。
今回はそれを、プレハブをインスタンス化したときに、実行したいメソッドを予め確保し必要に応じてそのメソッドを実行するようにします。
ヒエラルキーウィンドウ上ではオブジェクトが割り当てられているけど…
プレハブ化すると「なし」となってしまう
プレハブに実行したいメソッドを確保する方法
プレハブをインスタンス化した際に、以下のようにデリゲートを用いて実行したいメソッドを確保します。
public void Init(delFunc callback) {
UnityAction myClassListner = new UnityAction<MyClass>(callback);
myEvent.AddListener(myClassListner);
}
今回は独自クラスを使用しているのでとしていますが、stringやintでも大丈夫です。実行するメソッドの引数に合わせて変更しましょう。
スクリプトの準備
前回同様に実行のトリガーとなる「TestButton2.cs」と、引数を受け取るメソッドが書かれている「TestScript2」の2つを用意します。
スクリプトのコード
TestButton2.cs
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; public class TestButton2 : MonoBehaviour { [Serializable] private class MyEvent : UnityEvent<MyClass> { } [SerializeField] private MyEvent myEvent = null; public delegate void delFunc(MyClass myDelClass); public void Init(delFunc callback) { UnityAction<MyClass> myClassListner = new UnityAction<MyClass>(callback); myEvent.AddListener(myClassListner); } public void Click() { MyClass myClass = new MyClass(transform.name); myEvent.Invoke(myClass); } public class MyClass{ public string myNmae; public MyClass(string str) { myNmae = str; } } }
TestScript2.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class TestScript2 : MonoBehaviour { [SerializeField] private GameObject prefab = null; private void Start() { GameObject obj = Instantiate(prefab) as GameObject; obj.transform.SetParent(transform.parent.transform, false); obj.GetComponent<TestButton2>().Init(CallBack4); } public void CallBack4(TestButton2.MyClass myClass) { GetComponent<Text>().text = myClass.myNmae; } }
スクリプトの解説
TestButton2.cs
[Serializable] private class MyEvent : UnityEvent<MyClass> { }
[SerializeField] private MyEvent myEvent = null;
ここは前回と同じです。UnityEventで動的な引数を渡すために必要な記述となり、UnityEventを継承した独自クラスを宣言しています。
public delegate void delFunc(MyClass myDelClass);
デリゲートの宣言をしています。
「MyClass」を引数としたメソッドを確保するための準備となります。
public void Init(delFunc callback) {
UnityAction<MyClass> myClassListner = new UnityAction<MyClass>(callback);
myEvent.AddListener(myClassListner);
}
初期化処理の部分。プレハブからインスタンス化するときに、このメソッドを呼び出します。
その際、引数(delFunc callback)としてInvokeしたときに実行したいメソッドを受け取ります。
その受け取ったメソッド(callback)をAddlistenerでリスナー登録します。
こうしておくことで、Invokeしたときに引数として受け取ったメソッドを実行できるようになります。
public void Click() {
MyClass myClass = new MyClass(transform.name);
myEvent.Invoke(myClass);
}
ボタンをクリックしたときに呼ばれるメソッド。
自身のオブジェクト名を引数としてInvokeに渡しています。
ここで、「public void Init(delFunc callback)」で受け取り確保しておいたメソッドを実行しています。
TestScript2.cs
[SerializeField] private GameObject prefab = null;
プレハブ化しておいたボタンUIをスクリプトに登録するための変数。
private void Start() {
GameObject obj = Instantiate(prefab) as GameObject;
obj.transform.SetParent(transform.parent.transform, false);
obj.GetComponent<TestButton2>().Init(CallBack4);
}
ゲーム実行時にプレハブをインスタンス化しています。
そして「TestButton2.cs」のInitメソッドを実行しています。引数としてボタンがクリックされたときに実行してほしい「CallBack4」メソッドを渡しています。
public void CallBack4(TestButton2.MyClass myClass) {
GetComponent<Text>().text = myClass.myNmae;
}
Invokeされた際に呼ばれるメソッドです。このメソッドに”Invoke(値)”で指定した値が引数として渡されます。
引数として受け取れる型はInvokeする際に渡される型と合わせておく必要があります。
今回の場合は、「UnityEvent<MyClass> { }」としているため、MyClass型が引数として受け取ることができます。
そして受け取った引数をそのままテキストとして画面に表示します。
オブジェクトの準備
動作確認用にボタンUI、テキストUIをヒエラルキーウィンドウに追加しました。
作成したボタンに「TestButton2.cs」を、Textには「TestScript2.cs」をアタッチします。
さらに、ボタンをクリックした際にテキストオブジェクト引数を渡したいので、ボタンUIのクリックイベントに自分自身の「Click()」メソッドを指定しておきます。
ここまでできたら、ボタンUIをプロジェクトウィンドウにドラッグ&ドロップしプレハブ化します。
プレハブ化したらボタンUIは不要なので削除します。
最後にテキストUIにアタッチした「TestScript2」にボタンUIを割り当てます。
スポンサードサーチ
動作確認
再生ボタンでゲームを実行します。実行とともに作成されたボタンを押すと、押したボタンの名前がテキストに表示されます。
「TestScript2」が、ボタンのオブジェクト名を引数として受け取って画面に表示しているのが確認できます。
スポンサードサーチ
まとめ
デリゲートを使うことで少し複雑になっていますが、やっていることはシンプルです。
この方法を使うことでプレハブから複数ボタンを作成したときなどに、どのボタンが押されたかを簡単に取得できるようになります。
工夫次第でいろいろ使えそうですね!