コガネブログ

平日更新を目標にUnityやC#などのゲーム開発アレコレを書いていきます

【Unity】StartCoroutineでラムダ式を使用できるようにするラッパークラス

public class Character : MonoBehaviour
{
    private void Attack()
    {
        // エラー:yield ステートメントは、
        // 匿名メソッドまたはラムダ式の内部では使用できません
        StartCoroutine(() => 
        {
            yield return new WaitForSeconds(1);
            Debug.Log("攻撃");
        });
    }
}

StartCoroutine関数でラムダ式を使用するとエラーが出るため
短い処理だったとしても関数として定義する必要があります

public class Character : MonoBehaviour
{
    private void Attack()
    {
        StartCoroutine(DoAttack());
    }

    // うーん・・・
    private IEnumerator DoAttack()
    {
        yield return new WaitForSeconds(1);
        Debug.Log("攻撃");
    }
}

それが煩わしく感じたので下記のようなクラスを作成して
間接的にStartCoroutine関数でラムダ式を使えるようにしました

using System;
using System.Collections;
using UnityEngine;

/// <summary>
/// コルーチンに関する汎用クラス
/// </summary>
public static class CoroutineCommon
{
    private static readonly MonoBehaviour mMonoBehaviour;

    /// <summary>
    /// コルーチンを管理するゲームオブジェクトを生成するコンストラクタ
    /// </summary>
    static CoroutineCommon()
    {
        var gameObject = new GameObject("CoroutineCommon");
        GameObject.DontDestroyOnLoad(gameObject);
        mMonoBehaviour = gameObject.AddComponent<MonoBehaviour>();
    }

    /// <summary>
    /// 1 フレーム待機してから Action デリゲートを呼び出します
    /// </summary>
    public static void CallWaitForOneFrame(Action act)
    {
        mMonoBehaviour.StartCoroutine(DoCallWaitForOneFrame(act));
    }
        
    /// <summary>
    /// 指定された秒数待機してから Action デリゲートを呼び出します
    /// </summary>
    public static void CallWaitForSeconds(float seconds, Action act)
    {
        mMonoBehaviour.StartCoroutine(DoCallWaitForSeconds(seconds, act));
    }

    /// <summary>
    /// 1 フレーム待機してから Action デリゲートを呼び出します
    /// </summary>
    private static IEnumerator DoCallWaitForOneFrame(Action act)
    {
        yield return 0;
        act();
    }

    /// <summary>
    /// 指定された秒数待機してから Action デリゲートを呼び出します
    /// </summary>
    private static IEnumerator DoCallWaitForSeconds(float seconds, Action act)
    {
        yield return new WaitForSeconds(seconds);
        act();
    }
}
public class Character : MonoBehaviour
{
    private void Attack()
    {
        // 1 フレーム待機してから攻撃
        CoroutineCommon.CallWaitForOneFrame(() => Debug.Log("攻撃"));

        // 1 秒待機してから攻撃
        CoroutineCommon.CallWaitForSeconds(1, () => Debug.Log("攻撃"));
    }
}

短い処理をコルーチンで記述したい場合は役立つのかなと