Unity uGUIのボタンハンドリングをas3風味に


Unity の uGUI は便利なところも多いのですが、ボタン周りの扱いが as3と比べてだいぶめんどくさい感じ(そもそも DisplayObject ツリーでイベントフローも管理されている as3 と比べてめんどくさいというのもアレなんですが…)なので、できれば UI の構築はサクッと済ませて、演出や操作感のブラッシュアップに時間をかけたい僕としましては、ボタン周りのイベントハンドリングをもっと手軽にできないものかと思って、公式のリファレンスをほじくり返してみると…

見つかったのが EventTrigger を使用する方法でした。
EventTrigger には多数の EventTriggerType が実装されているので、これを as3 の EventType のように使用できればいい感じでコーディングできるようになるのではないかと思い、まずは公式リファレンスにある EventTrigger からコールバック関数を呼ぶコードを見てみました。

// イベントトリガーを取得
EventTrigger trigger = GetComponent<EventTrigger>();
// EventSystem のデリゲートリストに対するエントリーを作成
EventTrigger.Entry entry = new EventTrigger.Entry();
// コールバックとして受け取ったイベントと関連するのはどんなタイプのイベントかを設定
entry.eventID = EventTriggerType.PointerDown;
// EventTrigger.Entry にコールバックの関数を登録
entry.callback.AddListener( ( data ) => { OnPointerDownDelegate( (PointerEventData)data ); } );
// このイベントトリガーに登録されているすべての関数にEventTrigger.Entryを登録
trigger.triggers.Add( entry );

// コールバック関数
public void OnPointerDownDelegate( PointerEventData data )
{
	Debug.Log( "OnPointerDownDelegate called." );
}

うーむ。
確かにこれなんですが、これだと GetComponent() で EventTrigger コンポーネントを参照しているので、ボタンインスタンスにエディタ上で EventTrigger イベントIDを設定していないとエラーになりますよね。

これだといろいろ面倒なのでなんかいい方法がないか、できれば as3 の MouseEvent のような使い勝手にできないものかと公式のリファレンスを探ってみたのですが、EventTrigger.triggers のAPIリファレンスが見つからず詰みかけていたのですが…

なんと、こんな神記事を見つけてしまいました。
【Unity】スクリプトからuGUIのEventTriggerへリスナー登録する拡張を書きました

これですこれなんです。僕がやりたかったことは。
この記事にある拡張スクリプトをプロジェクトに登録しておくだけで、button.AddListener(EventTriggerType type, UnityAction callback) でボタンのイベントリスナーを立てることができます。

この記事の例では

button.AddListener(EventTriggerType.PointerUp, e => Debug.Log("PointerUp!"));

と、コールバックのデリゲートをラムダ式で書いてありますが、これをもっと as3 っぽい使い方にするには、

// リスナー
button.AddListener(EventTriggerType.PointerUp, onPointerUp);

// ハンドラ
void onPointerUp(BaseEventData e)
{
	Debug.Log("PointerUp!")); // ここまでは上記の例と同じ
	// さらに as3 っぽい使い方としては…
	Button btn = e.selectedObject; // これで as3 の e.currentTarget のようにボタンへの参照が取得できる
}

こんな感じで、BaseEventData.selectedObject で参照を取得したボタンにセットしたプロパティやメソッドにアクセスできるようになります。

これで UI の作成がだいぶ楽になりそうで助かりますね。