【Unity5】Input Moduleを自作した話
目次
前置き
こちらの記事は Unity 2 Advent Calendar 2016 の17日目記事です。
前回は私自身の記事「【Unity5】VRゲーム開発に役立つかもしれないアセットを二つ開発したので紹介と解説」でした。
また、その記事で自作アセットである「VRDebugConsole」について書きましたが、そのアセットではInputModuleを自作しています。今回はそのいきさつや中身について書くので、前日記事と合わせて拝読されることをお勧めします。
Input Moduleってなに?
さっそくですが、まずInput Moduleとは何か?
これは調べれば多数情報が出てきますが、要約すると、
ある入力に対するイベントの送信を行うもの
であると言えるでしょう(間違っていたら指摘をお願いします...)。
例えば、クリックやタップ、ドラッグやピンチアウト/イン等が当てはまるでしょう。クリックされた際に、選択されたボタン等のuGUIに対してイベントを送信、つまり、
いんぷっともじゅーる「おい、ぼたん君よ、君クリックされたで」
ぼたん「まじか処理実行するわ、あざす」
みたいな感じです。
実際には間にGraphic RaycasterなるuGUI検出用のレイキャスターが入るので、
もじゅーる「れいきゃすたー君、今ポインタは何かのuGUIにいる?」
れいきゃすたー「ちょいまち(レイ照射)...ぼたんの上にあるで」
もじゅーる「あざす」
もじゅーる「おい、ぼたん君よ、君クリックされたで」
ぼたん「まじか処理実行するわ、あざす」
みたいな流れだと思われます。
Unityには標準で搭載されており、それぞれ「Standalone Input Module」と「Touch Input Module」がありました。が、いつの間にかTouch Input Moduleは既にStandalone Input Moduleに統合されたようです。なのでStandalone Input Module一つでPCやモバイルの入力を賄えるようです(これ書くために調べるまで気づかなかった..)。
このコンポーネントは、uGUIを追加した際に自動生成される「EventSystem」にアタッチされています。
Input Moduleはつくれる
「Input Moduleは自作することが可能です。」
と、いうことを知った当時の私はVRDebugConsoleをVRデバイスで操作できるようにするために色々調べてみました。するとこちらの記事が見つかりました。
細かい関数の中身についてはこちらの記事を参考にしていただくとして、大まかにStandalone Input Moduleには以下の要素が含まれ、また記述されていることが分かります。
ここで、Standalone Input ModuleはPointer Input Moduleを継承していますが、これはマウスカーソルの情報を扱っているクラスのようです。そのため、マウス情報を用いない今回の場合はPointer Input Moduleは継承せず、そのさらに基底クラスである「Base Input Module」を継承します。これが、Input Moduleの大本となります。
どうやってInput ModuleはuGUIを判定しているのか?
ところで、Standalone Input ModuleはWorld座標に置いたuGUIに対してもイベントを送信出来ます(割と周知の事だったりするんでしょうか...私は最近気づきました)。
では、『Worldに置かれてようが置かれていまいがuGUIの上にマウスポインタがあるという認識をしている部分がどこかにあるはずだ』という事で、Pointer Input Moduleを見てみると、このようなコードがあります。
コードを見る限り、「PointerEventData」なる型の変数がマウスの情報となる変数群を持っているようです。そこに、マウスの座標や移動量などを割り当て、「eventSystem.RaycastAll(データ, レイキャスト結果のリスト配列)」に渡しレイキャストを飛ばす(Graphic Raycaster)ことで、uGUIを取得しています。
ということは、PointerEventDataの座標に対して、スクリーン座標を渡してやれば、任意にレイキャストを飛ばし、uGUIを取得することが出来るようになるという事です。後は、先ほどの「ExecuteEvents.Execute」関数に取得したuGUIと、作ったデータと、送信するイベントのタイプ(選択とかドラッグとか)を指定してやれば、uGUIの選択判定を実装できるはずです。
PointerEventDataを使う
というわけで実際にInput Moduleを自作したのが以下になります。
(他スクリプトと情報の受け渡しを行っているのでこれ単体では動きませんが...)
163行目で取得したuGUIに対してイベントを送信しているのがわかるかと思います。他にも、ラインレンダラで線を描画したりして選択個所を可視化しています。
結果、このようになります。
ただ、ポインタが今存在している位置を取得するためにuGUIに対してレイキャストを行って上動画のようにしたかったのですが、どうやらuGUIに普通のRaycastは衝突を検出しません。まぁGraphic Raycasterがわざわざ存在してるので当たり前なのかもしれませんが。
なので、VRDebugConsoleにウィンドウの形に沿ったコライダを追加し、そこにRaycastを飛ばして衝突検出させています。 他に何か良い方法があれば教えていただけると幸いです。まだ試していませんがGraphic Raycasterを使えばできるのかも?とは思っていますがどうなんでしょう...。