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 |
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 |
UniRx | 指定した型でエラーハンドルを発行する |
Repeat(Unit.Default) | UniRx | ループして任意の値で通知 ※終わり次第即座に次の通知を行います |
Create<Unit |
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>(); } }
参考サイト
これ書きかけです。 とりまここまで自分用に公開