【Unity】タップやドラッグなどのUIの入力処理をスクリプトから実行する【EventSystems】
はじめに
本記事の検証環境は以下になります。バージョンが違う場合には動作しない場合がありますので、ご留意ください。
- Unity 2022.3.0f1
- Unity UI 1.0.0
ExecuteEventsによる入力処理
ユーザーのここを押下した、長押しした、ドラッグした、といった入力処理は「UnityEngine.EventSystems.ExecuteEvents」を活用することで実現できます。
// どこかのタイミングでUIのカメラを渡す private Camera _camera; // クリック位置をPointerEventDataとして定義 var eventData = new PointerEventData(EventSystem.current) { // UI空間の座標から、実際の画面の入力座標に変換する position = RectTransformUtility.WorldToScreenPoint(_camera, target.position) }; // EventSystems.ExecuteEventsによるシミュレート ExecuteEvents.Execute(target.gameObject, eventData, ExecuteEvents.pointerClickHandler);
必要な情報は、
- 対象のGameObject
- 入力情報の定義となるPointerEventData
- 対象の入力を発火させるEventFunctor
になります。
3つ目のEventFunctorはPointerEventとしての種類を定義するための引数です。EventFunctor自体はExecuteEventsにpublic staticなメンバとして用意されています。基本的には、特定のイベントに合わせてこれらを呼び出します。
// ExecuteEvents内のEventFunctorの抜粋 public static EventFunction<IPointerMoveHandler> pointerMoveHandler { get { return s_PointerMoveHandler; } } public static EventFunction<IPointerEnterHandler> pointerEnterHandler { get { return s_PointerEnterHandler; } } public static EventFunction<IPointerExitHandler> pointerExitHandler { get { return s_PointerExitHandler; } } public static EventFunction<IPointerDownHandler> pointerDownHandler { get { return s_PointerDownHandler; } } public static EventFunction<IPointerUpHandler> pointerUpHandler { get { return s_PointerUpHandler; } }
クリック、押下の開始と終了、ドラッグなどなど、適宜UI操作に対応するIEventSystemHandlerに沿って、EventFunctorを選定します。
そして肝心なのがPointerEventDataです。入力する座標を始めとして多くの情報を定義できます。
最初のサンプルではRectTransformUtility.WorldToScreenPointによって変換した座標を渡しています。基本的にExecuteEventsの座標情報は、ワールド空間の座標をもとに、スクリーン空間の座標にしてやる必要があります。
たとえば、ドラッグ処理などを行う際には移動量の計算に必要となるpressPositionやdeltaを適宜設定する必要があります。
// ドラッグの始点と終点の定義 var startOffset = 0f; var endOffset = 100f; var targetPosition = target.transform.position; var startPositionWorld = targetPosition + startOffset; var endPositionWorld = targetPosition + endOffset; var startPosition = RectTransformUtility.WorldToScreenPoint(_camera, startPositionWorld); var endPosition = RectTransformUtility.WorldToScreenPoint(_camera, endPositionWorld); // 始点からドラッグ開始 ExecuteEvents.Execute(target.gameObject, eventData, ExecuteEvents.pointerDownHandler); ExecuteEvents.Execute(target.gameObject, eventData, ExecuteEvents.beginDragHandler); // durationにそって移動 var elapsedTime = 0d; while (elapsedTime < duration) { // ドラッグしたまま位置を調整 eventData.position = Vector2.Lerp(startPosition, endPosition, (float)(elapsedTime / duration)); ExecuteEvents.Execute(target.gameObject, eventData, ExecuteEvents.dragHandler); elapsedTime += Time.deltaTime; } // 終点でドラッグ終了 ExecuteEvents.Execute(target.gameObject, eventData, ExecuteEvents.endDragHandler); ExecuteEvents.Execute(target.gameObject, eventData, ExecuteEvents.pointerUpHandler);
選択操作やリストのスクロール操作なども適宜PointerEventDataとEventFunctorを渡せば実現できます。
おわりに
EventSystems.ExecuteEventsによってスクリプトから適宜UIの操作を実行することが可能でした。自動でUI操作を行いたい時など、場面はニッチですが活躍するのではないでしょうか。筆者は自動テストに用いています。
ここでまとめたExecuteEventsによる実装は、「【Unity】Anjinを使ってシーン中のuGUIを自動で操作する仕組み作り - うどんてっくメモ」という記事でも活用しています。 興味のある方は見てみてください。