Unityで使えるイベント

2021年12月3日

Unityで使えるイベントは、UnityイベントとC#のイベントの2つがあります。
Unityイベントでよく使われるのは、Buttonイベントでインスペクター から登録が可能です。
ここでは、ボタン以外でイベントを扱いたい場合について説明します。

Unityイベントチュートリアル

チュートリアルを通して、検証してみましょう

新しくUnityEventTestプロジェクトを作成します。

3Dでプロジェクトを作成します。

シーンをUnityEventSceneとして、保存します。

あとで、C#イベントも作成するため、シーンを分けます。

Cubeオブジェクトを作成します。

名前をPlayerにします。

PlayerController_UnityEventスクリプトを作成します。

このコードは、スペースキーを押下されたらメソッドを呼び出すものですが、どのメソッドが呼び出されるのかを記述していません。また、どこから呼び出されたのかもわかりません。スペースキーを押下すると何かのメソッドが呼び出されることがこのコードの目的になります。
このようなコードは、結びつきが弱い(依存性が低い)コードと言います。

コード

using UnityEngine;
using UnityEngine.Events;

public class PlayerController_UnityEvent : MonoBehaviour
{
    public UnityEvent OnCubeAction;

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            OnCubeAction?.Invoke();
        }
    }
}

コードの説明

イベントが発生した時に呼び出されるコードを代入するメンバーを宣言します。
OnCubeActionには、あとでメソッドを代入します。メソッドを代入できる変数をデリゲートと呼びます
(戻り値なし、引数なし)

public UnityEvent OnCubeAction;

?は、「もしnullでなければ」を略するもので、if(OnCubeAction != null)と同じです。
Invoke()で、メソッド(OnCubeAction)を呼び出します。
スペースキーを押下すると実行されます。

OnCubeAction?.Invoke();

CubeAction_UnityEventスクリプトを作成します。

コード

using UnityEngine;

public class CubeAction_UnityEvent : MonoBehaviour
{
    public void ColorChange()
    {
        GetComponent<Renderer>().material.color = Color.green;
    }

    public void Rotate()
    {
        transform.Rotate(Vector3.forward * 10);
    }
}

コードの説明

Cubeのカラーを緑にします

GetComponent<Renderer>().material.color = Color.green;

z軸を中心に10°回転します

transform.Rotate(Vector3.forward * 10);

Playerゲームオブジェクトに2つのスクリプトをアタッチします。

スクリプトをアタッチすると、インスペクター にコンポーネントの1つとして登録されます。
コンポーネントは、他にTransform,MeshRenderer,BoxColliderなどがあります。

イベントを登録します

インスペクター のPlayerController_UnityEventのOnCubeAction()に2つのメソッドを登録します
Unityイベント型のOnCubeActionメンバーには、複数のメソッドを登録することができます

実行してみましょう

スペースキーを押下すると、Cubeが緑になって、10°回転するか確認しましょう

Tips

インスペクターから登録しない方法
CubeAction_UnityEventスクリプトに次のコードを追記します。

private void Start()
{
    var action = GetComponent<PlayerController_UnityEvent>().OnCubeAction;

    action.AddListener(ColorChange);
    action.AddListener(Rotate);
}

インスペクターのマイナスボタンで登録したイベントを削除して確認しましょう

応用

イベントを宣言しているスクリプトとイベントと登録するスクリプトが別のオブジェクトにアタッチされている場合

objAにアタッチされているスクリプト

using UnityEngine;
using UnityEngine.Events;

public class EventSample : MonoBehaviour
{
    public UnityEvent actionEvent;

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

objBにアタッチされているスクリプト

インスペクターで登録する場合

objAのEventSampleコンポーネント(objAを選択して、インスペクターを確認)のイベントActionEvent欄に次の2つを登録します

using UnityEngine;

public class Act : MonoBehaviour
{
    public void AttackHandler()
    {
        Debug.Log("Show");
    }

    public void DiffencdHandler()
    {
        Debug.Log("Diffance");
    }
}

objBにアタッチされているスクリプト

インスペクターで登録しない場合

インスペクターのEventSampleにobjAをアウトレット接続しておきます
コードで追加する場合、AddListenerメソッドを使って登録します。
インスペクターでの登録と同様な処理となります。

using UnityEngine;

public class Act : MonoBehaviour
{
    [SerializeField]
    EventSample eventSample;

    private void Start()
    {
        eventSample.actionEvent.AddListener(AttackHandler);
        eventSample.actionEvent.AddListener(DiffencdHandler);
    }
    public void AttackHandler()
    {
        Debug.Log("Show");
    }

    public void DiffencdHandler()
    {
        Debug.Log("Diffance");
    }
}

イベントに引数を取りたい場合

イベントハンドラ側に情報を渡したい場合があります。その場合、引数として渡すことができます。

コード

using UnityEngine;
using UnityEngine.Events;

public class PlayerController_UnityEvent : MonoBehaviour
{
    public UnityEvent<string> OnCubeAction;

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            OnCubeAction?.Invoke("メッセージ");
        }
    }

    public void Show(string msg)
    {
        Debug.Log(msg);
    }
}

コードの説明

イベントが発生した時に呼び出されるコードを代入するメンバーを宣言します。
OnCubeActionには、あとでメソッドを代入します。メソッドを代入できる変数をデリゲートと呼びます
(戻り値なし、引数あり)
引数の型は、型パラメータとして設定します。この場合は、string型ですね。

public UnityEvent<string> OnCubeAction;

?は、「もしnullでなければ」を略するもので、if(OnCubeAction != null)と同じです。
Invoke()で、メソッド(OnCubeAction(引数))を呼び出します。
スペースキーを押下すると実行されます。

OnCubeAction?.Invoke("メッセージ");

今回は、サンプルとして、同じクラスにイベントハンドラを記述してみました。
もちろん、同じオブジェクトにアタッチされている別のスクリプトや別のオブジェクトにアタッチされているスクリプトを登録してもいいです。

public void Show(string msg)
{
    Debug.Log(msg);
}

イベントを登録します

インスペクター のPlayerController_UnityEventのOnCubeAction(String)にメソッドを登録します
Showは2つ存在しますので、コードで渡す引数が動的(処理によって内容を変えたい場合)では、Dynamic String側を選ぶようにします

渡す引数の値が固定値でいい場合

上記の設定選択で、Dynamic String ではなく、Static Parameters側を選びます。
メソッド欄の下側に空白が出てきますので、ここに記入します。
イベントハンドラ側には、このデータが渡されます。

C#イベントチュートリアル

C#で定義されているEventHandlerを使って、イベントを作成します。

シーンをDotNetEventとして、保存します。

プロジェクトビューで、新しくシーンを作成します。名前は、DotNetEventとします。

Cubeオブジェクトを作成します。

名前をPlayerにします。

PlayerController_DotNetEventスクリプトを作成します。

コード

using System;
using UnityEngine;

public class PlayerController_DotNetEvent : MonoBehaviour
{
    public event EventHandler OnCubeAction;

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            OnCubeAction?.Invoke(this, EventArgs.Empty);
        }
    }
}

コードの説明

OnCubeActionには、あとでメソッドを代入します。
(戻り値なし、引数 object sender, EventArgs e)イベントを発生させたインスタンスとその情報

public event EventHandler OnCubeAction;

?は、「もしnullでなければ」を略するもので、if(OnCubeAction != null)と同じです。
Invoke()で、メソッド(OnCubeAction)を呼び出します。
イベントを発生させたインスタンスは、このインスタンス自身とし、情報は特に提供しないため、Emptyとします。

OnCubeAction?.Invoke(this, EventArgs.Empty);

CubeAction_DotNetEventスクリプトを作成します。

コード

using System;
using UnityEngine;

public class CubeAction_DotNetEvent : MonoBehaviour
{
    private void Start()
    {
        PlayerController_DotNetEvent action = GetComponent<PlayerController_DotNetEvent>();

        action.OnCubeAction += ColorChange;
        action.OnCubeAction += Rotate;
    }

    public void ColorChange(object sender, EventArgs e)
    {
        GetComponent<Renderer>().material.color = Color.green;
    }

    public void Rotate(object sender, EventArgs e)
    {
        transform.Rotate(Vector3.forward * 10);
    }
}

コードの説明

PlayerController_DotNetEventコンポーネントを取得します。この名称は、クラス名(スクリプト名)と同じです。

PlayerController_DotNetEvent action = GetComponent<PlayerController_DotNetEvent>();
ポイント

インテリセンス(暗黙的な型の使用)で、型宣言をvarにすることで短く見やすくすることができます。

イベントを登録します

イベントが発生したら呼び出されるメソッドを登録します
PlayerController_DotNetEventクラスのOnCubeActionメンバーに呼び出したいメソッドを代入します。
+=で追加代入するイメージです。event では、=(イコール)での代入は許されていません。
-=でこのグループから外すことができます。

action.OnCubeAction += ColorChange;
action.OnCubeAction += Rotate;

Playerゲームオブジェクトに2つのスクリプトをアタッチします。

スクリプトをアタッチすると、インスペクター にコンポーネントの1つとして登録されます。
コンポーネントは、他にTransform,MeshRenderer,BoxColliderなどがあります。

実行してみましょう

スペースキーを押下すると、Cubeが緑になって、10°回転するか確認しましょう

おすすめ動画

ドキュメント

Unity

Posted by hidepon