イベントの仕組みと活用方法

本資料では、Unityにおけるイベントの仕組みとその活用方法について解説します。イベントを正しく理解し活用することで、コードの拡張性や保守性を高めることができます。


イベントとは

イベントとは、特定の「きっかけ」が発生したときに、あらかじめ登録されたメソッド(イベントハンドラ)が実行される仕組みのことです。

イベントのきっかけとなるもの

  • ボタンが押された
  • キー入力があった
  • タイマーで時間が経過した
  • オブジェクト同士が衝突した
  • その他のカスタムイベント

きっかけから実行したい処理

  • 計算処理
  • 得点の増加
  • ライフの減少
  • ゲームオーバー処理
  • 画面効果の発動 など

イベントを使わない実装方法と課題

シンプルな実装例

例えば、スペースキーの押下を「敵にやられた」と見立てて、以下のように実装します。

void Update()
{
    if (Input.GetKeyDown(KeyCode.Space))
    {
        Debug.Log("ライフが減った");
    }
}

この程度の処理であれば、特に問題なく実装できます。

機能追加による複雑化

しかし、機能追加に伴い処理が増えていくと、Updateメソッド内のifブロックが肥大化し、可読性や保守性が低下します。

void Update()
{
    if (Input.GetKeyDown(KeyCode.Space))
    {
        Debug.Log("ライフが減った");
        Debug.Log("もし、ライフが0ならゲームオーバー");
        Debug.Log("自分を消滅させる");
    }
}

更なる要望による問題点

追加の要望:

  • 派手な爆発アニメーションを実行したい
  • タイマーを一時停止したい
  • 背景を点滅させたい
  • 全ての敵のスピードを一時的に遅くしたい

これらを実装すると、以下の問題が発生します。

  • Updateメソッドが肥大化し、読みづらくなる
  • 他クラスのメソッド呼び出しが増え、依存関係が複雑になる
  • オブジェクト指向の設計原則に反し、拡張や修正が困難になる

イベントの活用

上記の問題を解決するために、イベントの仕組みを導入します。

4.1 基本的なイベントの実装

UnityEventを使用して、イベントを定義します。

using UnityEngine;
using UnityEngine.Events;

public class EventTrigger : MonoBehaviour
{
    public UnityEvent unityEvent;

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            unityEvent.Invoke();
        }
    }
}

4.2 イベントハンドラの登録方法

4.2.1 インスペクタでの登録

  1. EventTriggerスクリプトをゲームオブジェクトにアタッチします。
  2. インスペクタでUnityEventに実行したいメソッドを登録します。

Unity UIのボタンイベントと同様の手順で登録可能です。

4.2.2 コードでの登録

using UnityEngine;

public class UIController : MonoBehaviour
{
    public EventTrigger eventTrigger;

    void Awake()
    {
        eventTrigger.unityEvent.AddListener(ShowLife);
    }

    public void ShowLife()
    {
        Debug.Log("ライフの表示を更新");
    }
}
  • UIControllerスクリプトを適切なゲームオブジェクト(例:Canvas)にアタッチします。
  • eventTriggerに対象のEventTriggerオブジェクトをアサインします。

実行結果

ライフの表示を更新

4.3 引数を持つイベント

引数付きのイベントを使用する場合、UnityEvent<T0, T1, T2, T3>を用います(最大4つの引数まで)。

イベントの宣言と呼び出し

public UnityEvent<string, int> unityEvent;

void Update()
{
    if (Input.GetKeyDown(KeyCode.Space))
    {
        unityEvent.Invoke("スペース", 5);
    }
}

イベントハンドラの実装

public void ShowLife(string msg, int data)
{
    Debug.Log($"{msg} と {data}を受け取りました");
}

実行結果

スペース と 5を受け取りました

4.4 動的に生成されるオブジェクトでのイベント活用

Prefabから生成されるエネミーに対して、イベントを活用する例です。

using UnityEngine;

public class Enemy : MonoBehaviour
{
    EventTrigger eventTrigger;
    int speed;

    private void OnEnable()
    {
        eventTrigger = GameObject.Find("EventSystem").GetComponent<EventTrigger>();
        eventTrigger.unityEvent.AddListener(DecreaseSpeed);
    }

    private void OnDisable()
    {
        eventTrigger.unityEvent.RemoveListener(DecreaseSpeed);
    }

    public void DecreaseSpeed()
    {
        speed--;
    }
}
  • エネミーが生成されるたびに、イベントにハンドラを登録します。
  • エネミーが破棄されるときに、イベントからハンドラを解除します。

高度なイベント処理

さらに複雑な処理や条件分岐が必要な場合、Reactive Extensionsを利用することができます。

例:UniRxの活用

  • 最初の一回だけ特定の処理を行う
  • 特定の条件下で一度だけイベントを発火する
  • 複数のイベントを統合して処理する

参考リンク

UniRx勉強会〜実用例を見ながら〜 #C# – Qiita


参考資料

Unity,イベント

Posted by hidepon