はじめに
今回はコンポーネントに依存しないメソッドの実行方法についての記事になります!
UnityにはSendMessage
という一つのメッセージで複数の関数を起動するメソッドが備わっています。
具体的にはゲームオブジェクトにアタッチされている指定した名前と同じ全てのメソッドを呼び出すという動作をします。
おそらくよく使われるStart
・Update
などもこれで動作している?と勝手に思っていますが、正しいのはまだ分かっていないです。
これについて少し掘り下げてみましょう。
SendMessage
まずはSendMessage
の詳細を見てみましょう。
public void SendMessage (string methodName, object value= null, SendMessageOptions options= SendMessageOptions.RequireReceiver);
ここでの引数の詳細は以下の通りです。
引数名 | 意味 |
---|---|
methodName | 呼び出すメソッドの名前 |
value | 呼び出すメソッドに渡す値 |
options | ターゲットのオブジェクトにメソッドが存在しない場合、エラーを発生させるかどうか |
options
はSendMessageOptions
という列挙型を指定します。
名前 | 意味 |
---|---|
RequireReceiver | 必ず受信先がなくてはならない |
DontRequireReceiver | 受信先がなくてもよい |
SendMessageの使用例
実際に使った例を書いてみました。
Sender.cs
using UnityEngine; public class Sender : MonoBehaviour { private void Start() { gameObject.SendMessage("OnRecieve",10); //Reciever1: 10 Reciever2: 10 } }
Reciever1.cs
using UnityEngine; public class Reciever1 : MonoBehaviour { public void OnRecieve(int value) { Debug.Log("Reciever1: " + value); } }
Reciever2.cs
using UnityEngine; public class Reciever2 : MonoBehaviour { public void OnRecieve(int value) { Debug.Log("Reciever2: " + value); } }
ただ、このメッセージは非アクティブのゲームオブジェクトには送信されないことに気をつけてください。
MessageSystem
先程のSendMessage
には、自分で名前を入力することやリファクタリングしにくい、引数が一つのみなどの欠点をいっぱい抱えていました。
これを解決するために作られたのがMessageSystem
で、今から使うひとはこちらだけ覚えれば大丈夫です。
MessageSystem
で重要な要素はIEventSystemHandler
インターフェイス・ExecuteEvents.Execute
メソッドの二つです。
bool ExecuteEvents.Execute<T>(GameObject target, BaseEventData eventData, ExecuteEvents.EventFunction<T> functor);
ただBaseEventData
とExecuteEvents.EventFunction<T>
もなかなかに分かりづらいので詳細を見てみましょう。
BaseEventData
クラスは新しい EventSystem 内の全イベントタイプに共通する基本イベントデータを内包したクラスを指しているらしく、コンストラクタは以下の通りです。
public BaseEventData (EventSystems.EventSystem eventSystem);
EventSystems.BaseEventData - Unity スクリプトリファレンス
ここで分かればよかったのですが、新しくEventSystem
っていったいどんなや・・・という疑問が生まれてきてしまいました。
EventSystem
はuGUI
を作成すると自動で作成されるキーボード、マウス、タッチやカスタムの入力に基づいて、アプリケーション内のオブジェクトにイベントを送信する方法みたいです。
イベントシステム - Unity マニュアル
だんだん覚えることが多くて辛くなってくるかもしれませんが、実際にBaseEventData
を使うことはほとんどなく、基本はeventData
はnull
にしておいて大丈夫だと思います。
ただ使いたい場合は、最低限EventSystem.current
で現在のEventSystemを返すstatic変数があることだけ覚えればOKだと思います。
eventData: new BaseEventData(EventSystem.current)
またExecuteEvents.EventFunction<T>
は対象のインスタンス・EventDataを引数に持つラムダ式を指定します。(別にラムダ式じゃなくても良いですが)
functor: (reciever, eventData) => reciever.OnRecieve()
細かい説明はほどほどにして、実際に使った例を見てたほうが分かりやすいと思うのでみてみましょう。
MessageSystemの使用例
まずは引数なしの基本的なものの例を書いてみました。
IRecieveMessage.cs
using UnityEngine.EventSystems; public interface IRecieveMessage : IEventSystemHandler { void OnRecieve(); }
Sender.cs
using UnityEngine; using UnityEngine.EventSystems; public class Sender : MonoBehaviour { private void Start() { ExecuteEvents.Execute<IRecieveMessage>( target: gameObject, eventData: null, functor: (reciever, eventData) => reciever.OnRecieve() ); } }
Reciever1.cs
using UnityEngine; public class Reciever1 : MonoBehaviour , IRecieveMessage { public void OnRecieve() { Debug.Log("Recieve1"); } }
Reciever2.cs
using UnityEngine; public class Reciever2 : MonoBehaviour , IRecieveMessage { public void OnRecieve() { Debug.Log("Recieve2"); } }
引数ありの使用例
MessageSystem
の場合は無制限に引数が指定でき、以下のように実装します。
IRecieveMessage.cs
using UnityEngine.EventSystems; public interface IRecieveMessage : IEventSystemHandler { void OnRecieve(int value, string text); }
Sender.cs
using UnityEngine; using UnityEngine.EventSystems; public class Sender : MonoBehaviour { private void Start() { ExecuteEvents.Execute<IRecieveMessage>( target: gameObject, eventData: null, functor: (reciever, eventData) => reciever.OnRecieve(10, "value: ") ); } }
Reciever1.cs
using UnityEngine; public class Reciever1 : MonoBehaviour , IRecieveMessage { public void OnRecieve(int value, string text) { Debug.Log("Recieve1: " + text + value); } }
Reciever2.cs
using UnityEngine; public class Reciever2 : MonoBehaviour, IRecieveMessage { public void OnRecieve(int value, string text) { Debug.Log("Recieve1: " + text + value); } }
さいごに
これらを用いるとより疎結合ができる利点はありますが、特にSendMessage
は自分でメソッドの名前の書き間違いには要注意です。
また使ってみた感じExecuteEvents.EventFunction<T>
の第2引数のeventData
はほぼ使わない?というような気がしました。
もしこんな使い方があるというのを知っている方がいましたら、是非コメント等で教えていただけると嬉しいです!