Unityで他のスクリプトのメソッドを呼び出す3つの方法【ゲーム開発】
ゲームを作っていて、他のスクリプトのメソッドを使いたいケースは多々あります。Unityでシーン内のGameObjectにアタッチしたスクリプトを使う方法は主に以下の3つ方法があります。
- SendMessageを使う
- EventSystemsを使う
- GetComponentする
それぞれの方法についてメリット、デメリットを挙げ、使い分けができるように共有できればと思います。
SendMessageを使う
GameObject.SendMessage()を使って対象のゲームオブジェクトにあるメソッドを実行します。
メソッド名をstringで指定し、対象のオブジェクトにアタッチされたスクリプトで同じ名前のメソッドがあれば起動します。
例えば、メッセージを送信するゲームオブジェクトから、対象のゲームオブジェクトのメソッドを呼び出してみます。以下のスクリプトを別々のオブジェクトにアタッチしてゲームを実行すると、『SendMessageCaller』が『SendMessageTarget』の『ShowLog()』のスクリプトを呼び出してコンソールにメッセージが出力されます。
SendMessageCallerのスクリプト
SendMessageTargetのスクリプト
SendMessageのメリット
スクリプトのサンプルを見てもらうと分かる通り、呼び出し方が簡単なので実装しやすいです。
SendMessageのメソッドはGameObjectクラスに含まれているので、特別な準備なども必要ないのがいいですね。初心者向けのチュートリアルだとこの方法で別のスクリプトのメソッドを呼び出していることが多いように思います。
SendMessageのデメリット
文字列でメソッドを指定することから、対象のメソッド名が変わるとIDEでは検知できず、自力で気付く必要があります。
また、引数を1つしか指定できないのが痛いところ。しかし引数のためにstructなどを作っておけばいくつか渡せます。
SendMessageの総評
最近だとSendMessageを使っているという話はあまり聞かないような……?
Unityのマニュアルでも『EventSystemsはSendMessageを置き換えるために設計された』とあるので、次に紹介するEventSystemsを使用するのが主流だと思います。
EventSystemsを使う
メッセージシステムを使ってメソッドを呼び出します。
このメッセージシステムはuGUIで使われている方式で、例えばButtonコンポーネントなどでクリックやタップを検知してメソッドを呼びますが、あれもイベントシステムです。
こちらの方法ではインタフェースを使ってメソッドを実装するようにしています。
SendMessageの場合と同様に、メッセージを送信するゲームオブジェクトから、対象のゲームオブジェクトのメソッドを呼び出してみます。以下のスクリプトを別々のオブジェクトにアタッチしてゲームを実行すると、『EventSystemsCaller』が『EventSystemsTarget』の『EventCall()』のスクリプトを呼び出してコンソールにメッセージが出力されます。
また、インタフェースのスクリプトについては特定のオブジェクトにアタッチする必要はありません。
EventSystemsCallerのスクリプト
このスクリプトでは『NotifyEvent』のメソッドの中でExecuteEvents.Execute()を呼び出しています。(メソッド名はNotifyEventでなくても任意でつけて大丈夫です)
個人的にこの引数のラベルと引数の変数を対応する書き方が分かりやすかったのでこのような書き方にしています。functorは対象のインタフェースのどのメソッドを呼ぶかの指定で、上のように別のメソッドを作って呼んでもいいですし、ラムダ式で指定してもOKです。こちらも個人的に別のメソッドを作っておく方がやりやすかったのでこうしています。
EventSystemsTargetのスクリプト
メソッドを呼び出される側のスクリプトではインタフェースを実装し、対象のメソッドをpublicで作っておきます。こちら側はシンプルに実装できますね。
IEventCallerのスクリプト
インタフェースのスクリプトでは、classとして宣言するのではなくinterfaceとして宣言します。また、IEventSystemHandlerを継承します。usingで『UnityEngine.EventSystems』を宣言しておくことも忘れずに。
EventSystemsのメリット
SendMessageと比べると処理が早いのと、インタフェースを使ってメソッドの実装を強制するのでIDEでメソッド名の変更を追いやすいです。
引数の数も柔軟に対応できるのがグッド。
EventSystemsのデメリット
初心者だと書き方に迷うかもしれません。今だから言いますが、最初は何しているのか全く分かりませんでした(笑)
サンプルを見ながらひとつひとつ分解して確認していくことで理解できるようになります。
インタフェースのスクリプトを作成するのも初心者の立場からするとちょっと大変かも? とも思います。
EventSystemsの総評
慣れるまでは書き方に迷ったので、サンプルコードを見ながら真似して実装してみることをおすすめします。
ただプログラムとして見ると変更に強いというのは大きなメリットですし、パフォーマンス面でも優れているので個人的にはぜひこの方法をマスターして欲しいと思っています。
GetComponentする
コンポーネントを操作するときに使うGetComponentを使ってスクリプトを操作できるようにします。
これは一番簡単で分かりやすい方法です。
こちらもSendMessageやEventSystemsの場合と同様に、メッセージを送信するゲームオブジェクトから、対象のゲームオブジェクトのメソッドを呼び出してみます。以下のスクリプトを別々のオブジェクトにアタッチしてゲームを実行すると、『GetComponentCaller』が『GetComponentTarget』の『ShowLog()』のスクリプトを呼び出してコンソールにメッセージが出力されます。
GetComponentCallerのスクリプト
シンプルにGetComponentしてそのままメソッドを実行しています。publicなメソッドならこのように呼ぶことができます。
実際に使う場合はGetComponentの処理を何度も呼ばなくて済むようにフィールドに参照を保持(キャッシュ)しておくと良いでしょう。
GetComponentTargetのスクリプト
publicなメソッドとして用意しておくことで、他のスクリプトから呼び出すことができます。
GetComponentのメリット
スクリプトもGetComponentできるので、publicなメソッドを呼び出すことができます。普段コンポーネントを操作している時と同じような感覚で使えることから分かりやすいのがポイントです。
GetComponentのデメリット
publicにしているフィールドに値をセットすることもできるので注意が必要です。インスペクターウィンドウからオブジェクトなどをセットするためにpublicにすることがありますが、これを別のスクリプトからもできてしまう点は注意が必要です。
必要なのは1つのメソッドなのに、複数のフィールドやメソッドが公開されているのはオブジェクト指向の考え方からもよろしくありません。
使うなら自分ひとりで作っているゲームが良いかも。
また、シーン内に1つしかないオブジェクトにアタッチされたスクリプトをGetComponentするのはそこまで重くないですが、例えばシーンに10体いる敵キャラのコントローラースクリプトをGetComponentして操作します、だとちょっと重いですし、スクリプトも複雑になるかもしれません。この場合はEventSystemsを使った方がシンプルになることもあります。
GetComponentの総評
シンプルで分かりやすいのが好みです。
GetComponentはちょっと重い処理なので、もしやるならStart()のタイミングで参照をキャッシュしておくと吉。
使い分けの方針
個人的にはSendMessageは使ってなくて、ほぼEventSystemsを使って実装しています。
自分だけで作ってるゲームだったら、シーン内に1つしかないオブジェクトが対象ならGetComponentを使うこともあります。
その場合は必要なメソッドだけpublicにして、インスペクターウィンドウから値を変えたいフィールドはなるべく[SerializeField]にして隠蔽しています。
3日後の自分がアクセスしちゃうかもしれないですからね(笑)
3通りの方法で実装してみて、それぞれメリット・デメリットを踏まえた上で使い分けられるようになると良いでしょう。
ゲーム開発の攻略チャートを作りました!
-
前の記事
【Unity】ゲーム開発ではたまには高校数学も思い出すと便利です 2020.08.16
-
次の記事
【ゲーム開発】ゲームの遊び方が分かるヘルプ画面があると安心 2020.08.18
コメントを書く