柔軟性の高いマウスの入力管理クラスを作りたいと思い、UnityEventを使ってみた。
マウスの入力管理クラスにUnityEventを使うのが一般的かどうかはよくわからないが、とりあえず形になったのでメモを残しておく。
クラスを作った理由
今回作ったのは、オブジェクトに触れているときにマウスからの入力があれば、登録されているイベントを実行するクラス。
Unityを触ったことがある人は、「それEventTriggerで良くない?」と思うかもしれない。ですが、自分が作っていたプロジェクトではEventTriggerでの実装が難しく、MouseControllerクラスの実装に至った。
EventTriggerでの実装が難しい例
今回、以下の2点を理由にEventTriggerでの実装をやめた。逆に、ここで挙げている2点に該当しない場合はEventTriggerを使っていいかも。
- マウスがどのオブジェクトに触れているか、一つのクラスで管理したい場合
EventTriggerでわかるのはアタッチされているオブジェクトに対して操作があるかどうか。その情報をもとに管理するクラスに通知を送ってもいい気はするが、オブジェクト側に通知を送る関数を書かなきゃいけないのは不便。
マウス入力用のクラスを作り、そのクラスが触れているオブジェクトを取得したほうがシンプルでいいだろう。
- マウスが触れている座標を取得したい場合
実はEventTriggerからはマウスがオブジェクトのどこに触れているかは取得できない。取得したい場合は別の方法を考えなくてはならない。
今回のコードでは、Rayとの当たり判定をもちいて取得する。
使っていないので、詳しくは調べられていないが、座標の取得だけなら、EventSystemとIPointerEnterHandlerでも実装できるっぽい。IPointerEnterHandlerはイベントシステムのインターフェイスである。
参考ドキュメント
汎用性の追求
また、マウスからの入力を受け取るだけなら、わざわざUnityEventを導入する必要はない。UnityEventを導入したのは柔軟性を高めるためです。マウスの入力を受け取る専用のクラスをつくっておけばいろんなところで使える。
UnityEventを使えば、任意の関数やメソッドを登録しておき、それを実行できるようになるので汎用性の高いコードになる。
UnityEventとは
公式のドキュメントと解説してくれている人の記事を読むのが早い。
公式ドキュメント
解説記事
自分は関数を変数みたいな箱にいれて保持できるって感じに理解している。C#にもActionやEventがあるが、今回はメソッドが便利だったのでUnityEventを選んだ。
コードの概要
MouseControllerクラスでEventを定義し、それぞれの操作がされた際にアクションを実行するようになっている。
マウスとオブジェクトの当たり判定は以下の記事を参考にした。
RaycastHitでどのような値が取得できるかは以下のドキュメント参照。これらの値が扱えることもMouseControllerクラスを導入するメリットの一つ。
コード
MouseControllerクラス
今回はマウスは入ったとき、ドラッグされているとき、離されたときのみを実装しているが、Eventの種類を増やせば、他のマウス入力にも対応可能。
using System;
using UnityEngine;
using UnityEngine.Events;
public class MouseController : MonoBehaviour
{
public UnityEvent<RaycastHit> MouseOnEvent;
public UnityEvent MouseDragEvent;
public UnityEvent MouseUpEvent;
[SerializeField] private Camera cam;
void Update()
{
Ray ray = cam.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
MouseOnEvent?.Invoke(hit);
if (Input.GetMouseButton(0))
{
MouseDragEvent?.Invoke();
}
if (Input.GetMouseButtonUp(0))
{
MouseUpEvent?.Invoke();
}
}
}
}
マウス入力を受け取って処理をしたいクラス
まず、マウスコントローラーを取得し、変数に格納しておく。
[SerializeField] private MouseController mouseCS;
プロジェクトの任意の位置で、Eventを登録する。ここで、AddListenerの引数として渡すのは、登録したいメソッド名。Eventの登録と削除を使えば、実行されるメソッドを動的に変更することもできる。
mouseCS.MouseOnEvent.AddListener(MouseEnter);
mouseCS.MouseDragEvent.AddListener(MouseDrag);
mouseCS.MouseUpEvent.AddListener(MouseUp);
登録して、実行されるメソッドも定義しておく、MouseOnEventに登録するメソッドはRaycastHitを引数として持っているので登録するメソッドもRaycastHitを引数として持つようにする。
private void MouseEnter(RaycastHit hit)
{
// マウスが触れているときの処理
}
private void MouseDrag()
{
// マウスがドラッグされているときの処理
}
private void MouseUp()
{
// マウスが離されたときの処理
}
登録しているイベントを全部消して、一度リセットしたい場合は、RemoveAllListeners()メソッドを使う。
mouseCS.MouseOnEvent.RemoveAllListeners();
mouseCS.MouseDragEvent.RemoveAllListeners();
mouseCS.MouseUpEvent.RemoveAllListeners();