コガネブログ

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

【Unity】UniTask で非同期処理がすでに開始している場合は待機するだけのスクリプトメモ

コールバック版

using Kogane;
using System;
using UnityEngine;

public class Example : MonoBehaviour
{
    private readonly Hoge m_hoge = new Hoge();

    private void Update()
    {
        if ( Input.GetKeyDown( KeyCode.Z ) )
        {
            Hoge( "AAA" );
        }
        if ( Input.GetKeyDown( KeyCode.X ) )
        {
            Hoge( "BBB" );
        }
        if ( Input.GetKeyDown( KeyCode.C ) )
        {
            Hoge( "CCC" );
        }
    }

    private void Hoge( string message )
    {
        m_hoge.Play( () => Debug.Log( message ) );
    }
}

public class Hoge
{
    private enum State
    {
        IDLE,
        PLAYING,
        COMPLETE,
    }

    private Action m_onComplete;
    private State  m_state;

    public void Play( Action onComplete )
    {
        if ( m_state == State.COMPLETE )
        {
            onComplete();
            return;
        }

        if ( m_state == State.PLAYING )
        {
            m_onComplete += onComplete;
            return;
        }

        m_state = State.PLAYING;

        m_onComplete += onComplete;

        CoroutineUtils.CallWaitForSeconds
        (
            3, () =>
            {
                m_state = State.COMPLETE;

                m_onComplete();
                m_onComplete = null;
            }
        );
    }
}

UniTask 版

using Cysharp.Threading.Tasks;
using System;
using UnityEngine;

public class Example : MonoBehaviour
{
    private readonly Hoge m_hoge = new Hoge();

    private void Update()
    {
        Process().Forget();
    }

    private async UniTaskVoid Process()
    {
        if ( Input.GetKeyDown( KeyCode.Z ) )
        {
            await m_hoge.Play( () => UniTask.Delay( 3000 ) );
            Debug.Log( "AAA" );
        }

        if ( Input.GetKeyDown( KeyCode.X ) )
        {
            await m_hoge.WaitForCompletion();
            Debug.Log( "BBB" );
        }

        if ( Input.GetKeyDown( KeyCode.C ) )
        {
            await m_hoge.WaitForCompletion();
            Debug.Log( "CCC" );
        }
    }
}

public class Hoge
{
    private enum State
    {
        IDLE,
        PLAYING,
        COMPLETE,
    }

    private State                   m_state = State.IDLE;
    private UniTaskCompletionSource m_source;

    public async UniTask Play( Func<UniTask> action )
    {
        if ( m_state == State.COMPLETE )
        {
            Debug.Log( "完了済み" );
            return;
        }

        if ( m_state == State.PLAYING )
        {
            Debug.Log( "完了待ち" );
            await m_source.Task;
            return;
        }

        m_state = State.PLAYING;

        if ( m_source == null )
        {
            m_source = new UniTaskCompletionSource();
        }

        Debug.Log( "開始" );

        await action();

        Debug.Log( "完了" );

        m_state = State.COMPLETE;
        m_source.TrySetResult();
    }

    public async UniTask WaitForCompletion()
    {
        if ( m_state == State.COMPLETE )
        {
            Debug.Log( "完了済み" );
            return;
        }

        if ( m_source == null )
        {
            m_source = new UniTaskCompletionSource();
        }
        
        Debug.Log( "完了待ち" );
        await m_source.Task;
    }
}