LoginSignup
3
7

More than 5 years have passed since last update.

非同期処理を順番に処理する機能をUniRxで作る

Posted at

EventQueue.gif

シャドバのカード演出など,イベントキューがゲームで使われる機会はとても多いので作ってみました.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UniRx;
using System;

/// <summary>
/// 順番に非同期処理を処理していくクラス
/// </summary>
public class ObservableQueueWorker : IDisposable{

    bool running = false;
    List<Func<IObservable<Unit>>> eventQueue = new List<Func<IObservable<Unit>>> ();
    bool isDisposed = false;

    /// <summary>
    /// 非同期処理を追加
    /// </summary>
    public void Enqueue(Func<IObservable<Unit>> asyncAction){
        eventQueue.Add (asyncAction);
        if (!running) {
            running = true;
            SubscribeNext ();
        }
    }

    /// <summary>
    /// 先頭に割り込み
    /// </summary>
    public void InsertFirst(Func<IObservable<Unit>> asyncAction){
        if (running) {
            eventQueue.Insert (0, asyncAction);
        }else
            Enqueue (asyncAction);
    }

    /// <summary>
    /// 現在進行しているイベントが終わったらDisposeする
    /// </summary>
    public void EndLoop(){
        Debug.Log ("End Loop");
        InsertFirst (()=>Observable.Start(Dispose));
    }

    // 次のObservableを発火させる
    void SubscribeNext(){
        if (eventQueue.Count == 0 || isDisposed){
            Debug.Log ("Stop Running");
            running = false;
            return;
        }

        var e = eventQueue [0];
        eventQueue.RemoveAt (0);

        e ()
            .Finally (() => SubscribeNext ())
            .Subscribe ();
    }

    public void Dispose(){
        isDisposed = true;
    }
}

呼び出し側例


        var eventQueueWorker = new ObservableQueueWorker ();
        for (int i = 0; i < 10; i++) {
            int index = i;
            eventQueueWorker.Enqueue (()=>{
                Debug.Log(index);
                return Observable.Timer(TimeSpan.FromSeconds(1)).AsUnitObservable();
            });
        }

        Observable.Timer(TimeSpan.FromSeconds(2))
            .Subscribe(x=>eventQueueWorker.InsertFirst(()=>{
                Debug.Log("割り込み2秒");
                return Observable.Timer(TimeSpan.FromSeconds(2)).AsUnitObservable();
            }));

        Observable.Timer(TimeSpan.FromSeconds(6))
            .Subscribe(x=>eventQueueWorker.EndLoop());

まとめ

これから実際に使ってみてもっと欲しい機能があったら追加していきます.
改善できる点などあればコメントいただけると嬉しいです.

3
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
7