うどんてっくメモ

技術的なメモをまったりと

【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です。入力する座標を始めとして多くの情報を定義できます。

docs.unity3d.com

最初のサンプルでは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を自動で操作する仕組み作り - うどんてっくメモ」という記事でも活用しています。 興味のある方は見てみてください。