シャドバのカード演出など,イベントキューがゲームで使われる機会はとても多いので作ってみました.
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());
まとめ
これから実際に使ってみてもっと欲しい機能があったら追加していきます.
改善できる点などあればコメントいただけると嬉しいです.