UniRxとは
UniRx(Reactive Extensions for Unity)は、マイクロソフトによって開発された.NetFrameworkのReactive Extensions(Rx)機能をCySharp社がUnity用にしたライブラリです。
※UnityはMono(.NetFrameworkとは違う)環境をベースに動作しているため、.NetFrameworkのRxの機能をすべてサポートためです。
Rxとは、Observerパターンを取り入れたライブラリで、非同期 / イベント / 時間に関する処理をLINQ的に記述でき、プログラムをより効果的に管理するための機能を提供します。複雑なイベント処理をシンプルにし、コードの可読性や保守性を向上させることができます。
基本概念/機能
オブザーバブル(Observables):
データやイベントのストリームを表し、時間の経過と共に複数の値を非同期的に生成することができます。これにより、イベント駆動型のプログラミングが容易になります。
オブザーバー(Observers):
オブザーバーはオブザーバブルから送出されるデータを購読し、データが発行されるたびに特定のアクションを実行します。オブザーバーはオブザーバブルと接続され、イベントやデータの変更を監視します。
サブスクリプション(Subscriptions):
オブザーバーがオブザーバブルを購読するとき、サブスクリプションが生成されます。このサブスクリプションを通じて、イベントの購読を管理し、必要ない場合には購読を解除することができます。
オペレーター(Operators):
UniRxには多くのオペレーターが用意されており、これを使ってデータストリームの変換、フィルタリング、結合などが行えます。これにより、複雑なデータ処理や条件分岐を簡単に記述することが可能です。
利点
コードの簡素化: 非同期処理や複数のイベントソースを扱うコードが簡潔に書けるようになります。
エラー処理: エラーハンドリングが一元化され、エラー処理をストリーム内で簡単に行うことができます。
メモリリークの防止: イベントの購読解除を自動的に行うことで、メモリリークのリスクを減少させます。
時間操作: デバウンス、スロットル、タイムアウトなどの時間に基づいた操作を簡単に実装できます。
導入方法
以下のドキュメントより導入を行ってください。
github.com
基本的な利用方法
Obserbableの作成/設定
Obserbableすなわち、Observer(購読者)が読むもの/対象の作成をする必要があります。
Observableクラスのメソッドを利用してIObservable(インターフェース)として作成/設定します。
時間とイベントによるベースの設定があります。
以下はその種類です。
名前/記述 |
ディレクティブ |
内容 |
EveryUpdate(void) |
UniRx |
毎フレームごと(Updateタイミング)に通知 ※GameObjectの状態に依存しない全体サイクルをもとにします |
EveryLateUpdate(void) |
UniRx |
毎フレームごと(LateUpdateタイミング)に通知 ※GameObjectの状態に依存しない全体サイクルをもとにします |
EveryFixedUpdate(void) |
UniRx |
Unity設定で指定したフレームごと(FixedUpdateタイミング)に通知 ※通常と同様に物理計算系の使用に推奨 ※GameObjectの状態に依存しない全体サイクルをもとにします |
EveryGameObjectUpdate(void) |
UniRx |
|毎フレームごと(Updateタイミング)に通知 MainThreadDispatcherのSubjectに積まれて、メインスレッド実行になる |
EveryEndOfFrame(void) |
UniRx |
毎フレームの最後に通知 |
EveryApplicationFocus(void) |
UniRx |
アプリのフォーカス状態が変更されるたびに通知 戻り値がboolでフォーカス状態が判る true : フォーカス中 false : フォーカス外 |
EveryApplicationPause(void) |
UniRx |
アプリが一時停止時に通知 戻り値がboolで停止状態が判る true : 停止 false : 再開 |
Range(int, int) |
UniRx |
指定した範囲の整数で順に通知する 第一引数が開始値、第二引数が回数 例 (3,4) = {3, 4, 5, 6} |
Start(Func <T> or Action) |
UniRx |
指定した処理を非同期実行し、結果を通知 |
Interval(TimeSpan) |
UniRx, System |
指定した時間間隔で通知 |
Timer(TimeSpan) |
UniRx, System |
指定した時間経過後に通知 引数によって単発や一定間隔での通知にできる |
Timer(TimeSpan) |
UniRx, System |
指定したフレーム経過後に通知 引数によって単発や一定間隔での通知にできる |
UpdateAsObservable() |
UniRx.Triggers |
MonoBehaviourのUpdate()の呼び出しをObservableストリームとして扱い、通知する |
LateUpdateAsObservable() |
UniRx.Triggers |
MonoBehaviourのLateUpdate()の呼び出しをObservableストリームとして扱い、通知する |
FixedUpdateAsObservable() |
UniRx.Triggers |
MonoBehaviourのFixedUpdate()の呼び出しをObservableストリームとして扱い、通知する |
OnDestroyAsObservable() |
UniRx.Triggers |
MonoBehaviourのOnDestroy()の呼び出しをObservableストリームとして扱い、通知する |
ObserveEveryValueChanged (TSource, Func<TSource, TProperty>) |
UniRx |
指定したプロパティが変更時に通知 |
Empty<Unit>() |
UniRx |
指定した型で即座に通知 |
Return(Unit.Default) |
UniRx |
指定した値で即座に通知 |
Throw<Unit>(new Exception()) |
UniRx |
指定した型でエラーハンドルを発行する |
Repeat(Unit.Default) |
UniRx |
ループして任意の値で通知 ※終わり次第即座に次の通知を行います |
Create<Unit>(observer => ...) |
UniRx |
独自の通知条件の作成 |
※UnitはUniRxで通知の際の値や型がない場合に使用する構造体です。
Unitの部分は任意の型、Unit.Defaultは具体的な任意な型の値を設定できます。
using System;
using UniRx;
using UniRx.Triggers;
using UnityEngine;
public class UniRxTest : MonoBehaviour
{
void Start()
{
Observable.Interval(TimeSpan.FromSeconds(1));
Observable.Timer(TimeSpan.FromSeconds(1));
Observable.TimerFrame(1);
Observable.EveryUpdate();
Observable.EveryLateUpdate();
Observable.EveryFixedUpdate();
Observable.EveryGameObjectUpdate();
Observable.EveryEndOfFrame();
Observable.EveryApplicationFocus();
Observable.EveryApplicationPause();;
Observable.Range(0, 10);
Observable.Start(() => { });
this.UpdateAsObservable();
this.LateUpdateAsObservable();
this.FixedUpdateAsObservable();
this.OnDestroyAsObservable();
this.ObserveEveryValueChanged(self => self.transform.position);
Observable.Empty<Unit>();
Observable.Return(Unit.Default);
Observable.Throw<Unit>(new Exception());
Observable.Repeat(Unit.Default);
Observable.Create<Unit>(observer =>
{
return Disposable.Empty;
});
}
}
Obserbableの処理をフィルタリング設定のオペレーターがあります。
以下はその種類です。
名前/記述 |
内容 |
Where |
条件式に一致したもののみ |
Distinct |
重複した二つ目以降は通さない |
DistinctUntilChanged |
最新のものが同じだった場合通さない |
Throttle/ThrtottleFrame |
指定した時間(ms)/フレーム内に来たOnNextの最後だけ通す |
ThrottleFirst/ThrottleFirstFrame |
指定した時間(ms)/フレーム内に来たOnNextの最初だけ通す |
First/FirstOrDefault |
一番最初のみを通してObservableを完了 ※一つも発行されなかったとき通常はエラー、Defaultはデフォルト値で通知 |
Single/SingleOrDefault |
OnNextが2つ以上発行されたらエラー ※一つも発行されなかったとき通常はエラー、Defaultはデフォルト値で通知 |
Last/LastOrDefault |
最後の値だけ通したい ※一つも発行されなかったとき通常はエラー、Defaultはデフォルト値で通知 |
Take |
指定した個数だけ通す |
TakeWhile |
条件不一致になるまで通す |
TakeUntil |
指定したObservableにOnNextが来るまで通す |
Skip |
指定した個数無視 |
SkipWhile |
条件一致する間は無視 |
SkipUntil |
指定したObservableにOnNextが来るまで無視 |
OfType |
型が一致するもののみ通す※型変換も行われます |
IgnoreElements |
OnErrorまたはOnCompletedのみを通す |
using System;
using UniRx;
using UniRx.Triggers;
using UnityEngine;
public class EventBase { }
public class Event : EventBase { }
public class UniRxTest : MonoBehaviour
{
void Start()
{
this.UpdateAsObservable()
.Where(_ => Input.GetKeyDown(KeyCode.Space))
.Distinct()
.DistinctUntilChanged()
.Throttle(TimeSpan.FromSeconds(1))
.ThrottleFrame(1)
.ThrottleFirst(TimeSpan.FromSeconds(1))
.ThrottleFirstFrame(1)
.TimeInterval()
.Timeout(TimeSpan.FromSeconds(1))
.TimeoutFrame(1)
.First()
.FirstOrDefault()
.Single()
.SingleOrDefault()
.Last()
.LastOrDefault()
.Take(1)
.TakeWhile(_ => Input.GetKey(KeyCode.Space))
.TakeUntil(this.LateUpdateAsObservable())
.Skip(1)
.SkipWhile(_ => Input.GetKey(KeyCode.Space))
.SkipUntil(this.LateUpdateAsObservable())
.IgnoreElements();
Subject<EventBase> subject = new Subject<EventBase>();
subject.OfType<EventBase, Event>();
}
}
参考サイト
qiita.com
これ書きかけです。
とりまここまで自分用に公開