Unity_Lesson

について

1. 通常の利用方法


2. 引数を取る場合 (複数の引数を取る場合も含む)

各デリゲートやイベントで、引数を取る場合の例です。

Action

using System;
public Action<string, int> onAction;

void Start()
{
    onAction += (message, number) => Debug.Log($"{message} - {number}");
    onAction?.Invoke("Message", 42);
}


EventHandler

public event EventHandler<CustomEventArgs> onEvent;
public class CustomEventArgs : EventArgs { public string Message; public int Number; }

void Start()
{
    onEvent += (sender, e) => Debug.Log($"{e.Message} - {e.Number}");
    onEvent?.Invoke(this, new CustomEventArgs { Message = "Event message", Number = 42 });
}

Delegate

public delegate void CustomDelegate(string message, int number);
public CustomDelegate onCustomEvent;

void Start()
{
    onCustomEvent += (message, number) => Debug.Log($"{message} - {number}");
    onCustomEvent?.Invoke("Delegate message", 42);
}

UnityEvent

using UnityEngine.Events;
public UnityEvent<string, int> onUnityEvent;

void Start()
{
    onUnityEvent.AddListener((message, number) => Debug.Log($"{message} - {number}"));
    onUnityEvent?.Invoke("UnityEvent message", 42);
}

Func

public Func<string, int, string> onFunc;

void Start()
{
    onFunc += (message, number) => $"{message} - {number}";
    string result = onFunc?.Invoke("Func message", 42);
    Debug.Log(result);
}

3. 戻り値を取る場合

ActionEventHandlerUnityEvent戻り値を持ちませんが、FuncやカスタムDelegateを使うことで戻り値を持たせることが可能です。

Func (戻り値あり)

public Func<string, int, string> onFunc;

void Start()
{
    onFunc += (message, number) => $"{message} - {number}";
    string result = onFunc?.Invoke("Func message", 42);
    Debug.Log(result); // 出力: Func message - 42
}

Delegate (戻り値あり)

public delegate int CustomDelegate(string message, int number);
public CustomDelegate onCustomEvent;

void Start()
{
    onCustomEvent += (message, number) => message.Length + number;
    int result = onCustomEvent?.Invoke("Hello", 5);
    Debug.Log(result); // 出力: 10
}

4. 違いや使い所についてのまとめ

特徴 Action EventHandler Delegate UnityEvent Func
戻り値 なし なし 任意 なし あり
引数 最大16個 EventArgsを使って渡す 任意 UnityEvent<T>形式で設定 最大16個
インスペクター対応 なし なし なし あり なし
使いどころ シンプルなイベント処理 C#の標準的なイベント カスタム処理や複雑なパターン Unityエディターでイベント設定したい場合 戻り値が必要な場合

使い所まとめ:

  1. Action:
    • シンプルなイベント処理や、戻り値が不要な場合に便利。
    • 引数を使った汎用的なイベント処理に向いています。
  2. EventHandler:
    • 標準的なC#イベント。複数のリスナーやイベント発生元、追加データ (EventArgs) を伝えたい場合に使用します。
    • 複雑なイベントのやり取りが必要な場面で使いやすいです。
  3. Delegate:
    • カスタムのデリゲートを定義したい場合。引数や戻り値を自由に定義でき、柔軟なイベント処理を構築できます。
    • 特定の処理に合わせたイベントや、シグネチャを細かくカスタマイズしたいときに適しています。
  4. UnityEvent:
    • Unityのエディターからも設定可能なイベントシステム。インスペクターからイベント設定ができるため、スクリプトに依存せずイベント処理を追加・管理したい場合に最適です。
    • UIやゲームオブジェクトのインタラクションに向いています。
  5. Func:
    • 戻り値が必要なイベントやデリゲートを使いたい場合に適しています。
    • 例えば、処理の結果を返したり、データを計算して返す必要がある場合に使います。

サンプルコード

ActionEventHandlerDelegateUnityEventFuncを使ったサンプルコード




1. Action の利用例

using UnityEngine;
using System;

public class ActionExample : MonoBehaviour
{
    // 引数付きのAction (stringとintを受け取る)
    public Action<string, int> onAction;

    void Start()
    {
        // Actionにメソッドを登録
        onAction += PrintMessage;

        // Actionを実行
        onAction?.Invoke("Hello from Action", 42);
    }

    void PrintMessage(string message, int number)
    {
        Debug.Log($"{message} - {number}");
    }
}




2. EventHandler の利用例

using UnityEngine;
using System;

public class EventHandlerExample : MonoBehaviour
{
    // カスタムEventArgsクラス
    public class CustomEventArgs : EventArgs
    {
        public string Message { get; set; }
        public int Number { get; set; }
    }

    // EventHandler (CustomEventArgsを使う)
    public event EventHandler<CustomEventArgs> onEvent;

    void Start()
    {
        // EventHandlerにメソッドを登録
        onEvent += OnEventTriggered;

        // イベントを発生させる
        onEvent?.Invoke(this, new CustomEventArgs { Message = "Hello from EventHandler", Number = 42 });
    }

    void OnEventTriggered(object sender, CustomEventArgs e)
    {
        Debug.Log($"{e.Message} - {e.Number}");
    }
}




3. Delegate の利用例

using UnityEngine;

public class DelegateExample : MonoBehaviour
{
    // カスタムデリゲート (stringとintを受け取り、intを返す)
    public delegate int CustomDelegate(string message, int number);

    // カスタムデリゲートの変数
    public CustomDelegate onCustomEvent;

    void Start()
    {
        // デリゲートにメソッドを登録
        onCustomEvent += CalculateStringLengthAndAddNumber;

        // デリゲートを実行し、結果を取得
        int result = onCustomEvent?.Invoke("Hello from Delegate", 42) ?? 0;
        Debug.Log($"Result: {result}");
    }

    // stringの長さとnumberを足して返す
    int CalculateStringLengthAndAddNumber(string message, int number)
    {
        return message.Length + number;
    }
}




4. UnityEvent の利用例

using UnityEngine;
using UnityEngine.Events;

public class UnityEventExample : MonoBehaviour
{
    // 引数付きのUnityEvent (stringとintを受け取る)
    public UnityEvent<string, int> onUnityEvent;

    void Start()
    {
        // UnityEventにリスナーを登録
        onUnityEvent.AddListener(PrintMessage);

        // UnityEventを実行
        onUnityEvent?.Invoke("Hello from UnityEvent", 42);
    }

    void PrintMessage(string message, int number)
    {
        Debug.Log($"{message} - {number}");
    }
}




5. Func の利用例

using UnityEngine;
using System;

public class FuncExample : MonoBehaviour
{
    // 戻り値付きのFuncデリゲート (stringとintを受け取り、stringを返す)
    public Func<string, int, string> onFunc;

    void Start()
    {
        // Funcにメソッドを登録
        onFunc += FormatMessage;

        // Funcを実行し、戻り値を取得
        string result = onFunc?.Invoke("Hello from Func", 42);
        Debug.Log(result);
    }

    // stringとintを受け取り、整形されたメッセージを返す
    string FormatMessage(string message, int number)
    {
        return $"{message} - {number}";
    }
}




6. それぞれの使い所のまとめ

種類 用途 Unityインスペクターで設定可能 戻り値 引数
Action シンプルなイベント処理に最適。戻り値は不要。 なし なし 最大16個
EventHandler 標準的なイベントシステム。イベント発生元やデータの管理が必要な場合。 なし なし EventArgsで管理
Delegate 自由な引数・戻り値を設定可能なカスタムイベント。 なし あり 任意
UnityEvent Unityエディターでイベントを設定したい場合。UIなどのイベント管理に最適。 あり なし 最大4つまで
Func 戻り値が必要な場合に使用。結果を返す処理に向いている。 なし あり 最大16個







ファイルを分けて書く

実際の開発では、スクリプトが別ファイルに分かれることが多いです。特に、以下のようなケースではファイルを分けることが推奨されます。

1. クラスやデリゲートの再利用

2. 機能ごとに分ける

3. Unityの実践的なプロジェクト構成




実際にファイルを分けた例

1. CustomEventArgs.cs

using System;

public class CustomEventArgs : EventArgs
{
    public string Message { get; set; }
    public int Number { get; set; }
}

2. EventInvoker.cs(イベントを発生させるクラス)

using UnityEngine;

public class EventInvoker : MonoBehaviour
{
    // イベントの宣言
    public event EventHandler<CustomEventArgs> onEvent;

    void Start()
    {
        // イベントを発生させる
        TriggerEvent();
    }

    void TriggerEvent()
    {
        if (onEvent != null)
        {
            onEvent.Invoke(this, new CustomEventArgs { Message = "Hello from Invoker", Number = 99 });
        }
    }
}

3. EventListener.cs(イベントを受け取るクラス)

using UnityEngine;

public class EventListener : MonoBehaviour
{
    public EventInvoker invoker;

    void OnEnable()
    {
        if (invoker != null)
        {
            // イベントのリスナーを登録
            invoker.onEvent += OnEventTriggered;
        }
    }

    void OnDisable()
    {
        if (invoker != null)
        {
            // イベントのリスナーを解除
            invoker.onEvent -= OnEventTriggered;
        }
    }

    void OnEventTriggered(object sender, CustomEventArgs e)
    {
        Debug.Log($"Received event: {e.Message} - {e.Number}");
    }
}
  1. コードの再利用がしやすくなり、複数のスクリプトから共通の機能を利用可能。
  2. 責任の分離により、各クラスの役割が明確になり、保守性が向上。
  3. イベント管理が整理され、プロジェクト全体の構成がスッキリとします。