ゲーム化!tomo_manaのブログ

ゲーム化!tomo-manaのブログ

Unityでゲームを作る方法について紹介しています

Unity学習#34-2 EventSystemとInputSystemUIInputModule (Unity 2019.4.4f1)

第12回でInputSystemについて、第13回でEventSystemについて、それぞれ調べました。複数シーンでゲームを構成する場合は、もう少し深掘りが必要なことが分かったので、再度いくつか疑問に思っていたことについて調べました。


全体として知りたいのは、EventSystemからPlayerInput経由でメッセージを受け取るまでの流れです。

今回は、EventSystem と InputSystem 用のコンポーネント InputSystemUIInputModule との関係について。

特に、(1) 複数のシーンでゲームが構成されている場合、EventSystemはシーン毎に置いても正しく動作するのか。また、(2) InputManager から InputSystem に変える時に StandaloneInputModule から InputSystemUIInputModule に置き換えましたが、この二つはどんな繋がりがあるのか。EventSystemはそもそも何をしていて、InputSysmteUIInputModule は何をしているのか。この2つについて調べました。

動機は、シーンが複数ある場合に、EventSystem をどのように配置したら良いかを知りたかったからでした。

結論

こんな感じでした。

(1) EventSystem は、シーン毎に一つずつあっても正常に動作します排他制御)。
(2) EventSystem は StandaloneInputModule と InputSystemUIInputModule の共通ベースクラス BaseInputModule を参照しています。また、InputSystemUIInputModule は、入力イベントの「状態管理」しています。EventSystem は BaseInputModule の排他制御をしています。


以下は EventSystem と InputSystemUIInputModule(BaseInputModule) の関係を表した図です。

f:id:tomo_mana:20210622003533j:plain
イメージ

EventSystem

まず、EventSystem が何をしているか。
EventSystem は、InputManager または InputSystem による入力監視処理が、一つだけ呼び出されるようにしています(排他制御)。また、EventSystem は現在選択されているゲームオブジェクト(SelectedGameObject)を保持する箱でもあり、選択が変更されたときにゲームオブジェクトに変更を伝えます(ISelectHandler、IDeselectHandler)。

EventSystem同士の連携(リスト化・排他制御

同一ゲーム内に複数のEventSystem があった場合、現在有効な EventSystem 以外は動かないようになっています。現在有効な EventSystem は、シングルトンである current です。(EventSystem.current)

f:id:tomo_mana:20210619225547p:plain
EventSystem管理(シングルトン構造)

この current と、現在アクセス可能な EventSystem たちを管理するシングルトンのリスト m_EventSystems があります。この EventSystemのリスト は、EventSystem コンポーネントを持つゲームオブジェクトがアクティブになった時に登録され、非アクティブになった時に登録解除されます。先述の current は、このリストの先頭にいる EventSystem です。

f:id:tomo_mana:20210619225635p:plain
EventSystemへの登録と解除、有効化

この リスト は private なので、EventSystem の外から リスト を直接書き変えることはできません。その代わりに、シーンが切り替わった時など、EventSystemを切り替える場合は、current にこれから使いたい EventSystem をセットします。これで、current にセットした EventSystem は、このリストの先頭になります。

InputManager と InputSystem の互換性

従来の入力システムである InputManager と、新しい入力システムである InputSystem 間の互換性は、両者の上位クラス BaseInputModule を用意することで吸収しています。

f:id:tomo_mana:20210619231232p:plain
EventSystemとBaseInputModule

このBaseInputModuleを継承したクラスは、入力が確定した時に、IEventSystemHandler を持つゲームオブジェクトにメッセージを伝える役割を果たします。また、入力が確定したことを調べるため、入力状態を管理(トレース)しています。例えばボタンを押した/離した、ドラッグした/離した、などです。
尚、InputSystemUIInputModule は、Navigation と呼ばれる仕組みを一緒に管理しています。これは経路探索などで使用できるようですが、まだ調べていないので、以下のリンクを参考に貼っておきます。
【Unity】Navigationを使って経路探索させる - Qiita

EventSystem と InputSystemUIInputModule の関係

EventSystem の役目

EventSystem は、InputSystemUIInputModule にとって、タイマーのような役目を果たします。

f:id:tomo_mana:20210619233914p:plain
EventSystemからのトリガ(Update)

EventSystem は、それ自身がコンポーネントのため、MonoBehavior(UIBehavior) を継承しています。MonoBehavior を継承するクラスは、UnityシステムからのUpdate()イベントを受信します。EventSystem は、このUpdate() のタイミング毎に、現在有効なInputSystemUIInputModule に、入力状態の確認(Process())を依頼します。

InputSystemUIInputModule 自身もコンポーネント(BaseInputModule が UIBehaviorを継承)のため、Update() を受け取れそうなものですが、EventSystem からのキックを待って動くようにできています。これは EventSystem側 で、BaseInputModule を排他制御させたいためと思われます。

EventSystem -> InputSystemUIInputModule

尚、EventSystem が InputSystemUIInputModule を一方的に参照している(親子)関係です。(が、InputSystemUIInputModule も、EventSystem にメッセージを投げることがあります)

f:id:tomo_mana:20210619233238p:plain
EventSystemとInputSystemUIInputModule


EventSystem から見て、現在有効なInputSystemUIInputModule は、リスト(m_CurrentInputModule)に保存されています。これはシングルトンではなく、各 EventSystemコンポーネント が持っています。

f:id:tomo_mana:20210619232916p:plain
EventSystem内のBaseInputModule群

EventSystem は、自分と同じゲームオブジェクト内の全ての InputSystemUIInputModule を認識します。ただし、複数の InputSystemUIInputModule があっても、有効な InputSystemUIInputModule は一つだけです。

ちなみに、このリストは GetComponent() で取得してくるだけで、登録順の入れ替えなどは特にしていないようですので、できれば EventSystem と同一ゲームオブジェクト内に BaseInputModule は一つだけ存在しているのが無難です。


これまでの内容を繋げると、冒頭の図になります。

f:id:tomo_mana:20210622003533j:plain


これで、複数シーンが起動していても、有効なEventSystems は常に一つであることが担保されています。また、有効な InputSystemUIInputModule も一つだけ、ということになります。

EventSystem <- InputSystemUIInputModule

EventSystem が InputSystemUIInputModule を一方的に参照している(親子)関係ですが、InputSystemUIInputModule も、EventSystem にメッセージを投げることがあります。それは、InputSystemUIInputModule が、ゲームオブジェクトの選択状態が変わったことを察知した時です。

InputSystemUIInputModule は、EventSystem.SetSelectedGameObject() を利用して、EventSystem にゲームオブジェクトの選択状態の変更を伝えます。その意味で、EventSystem と InputSystemUIInputModule は連携して動きます。


(以上)