SlideShare a Scribd company logo
UniRxことはじめ
KLab株式会社 安井彰一
自己紹介
名前:安井彰一
経歴:コンソールゲームプログラマ5年
ネットワークゲームエンジニア3年
昨年9月 KLab入社
(Uni)Rx歴3ヶ月
本稿の対象者
Linqがある程度読める人 ( C# )
Rxの資料は読んだがまだ書いたことがない人
注釈
本稿ではUniRxを題材に扱いますが、
その他のRx実装でも同様の考え方ができます。
ただし、メソッド名などが違う場合が
ありますのでご注意ください。
アジェンダ
・(Uni)Rxとは
・Rxの利点
・Rxの問題点
・UniRxの導入いろは
・デバッグ方法
・まとめ
アジェンダ
・(Uni)Rxとは
・Rxの利点
・Rxの問題点
・UniRxの導入いろは
・デバッグ方法
・まとめ
UniRxとは
Rx(Reactive Extensions)の
Unity実装です。
Rxとは
(Reactive Extensions)
イベントの流れ及びその制御を
LINQのような書式で
簡潔に書けるようにしたもの。(意訳)
Rxの実装リスト
Rx.NET
RxJS
RxJava ( RxAndroid )
ReactiveCocoa
Rx.py
など
ReactiveExtensionsとは
プログラミング手法のこと。
C#だけのものではありません。
アジェンダ
・(Uni)Rxとは
・Rxの利点
・Rxの問題点
・UniRxの導入いろは
・デバッグ方法
・まとめ
Rxの利点
時間を簡単に扱える
例題
例題A
マウスを押しっぱなしにしている間、
数値をカウントアップさせる。
Rxではない実装
class Hoge : MonoBehaviour {
public int Count { get; private set; }
public void Update() {
bool mouseDown = Input.GetMouseButtonDown(0);
if ( mouseDown ) {
++Count;
}
}
}
Rxではない実装
class Hoge : MonoBehaviour {
public int Count { get; private set; }
public void Update() {
bool mouseDown = Input.GetMouseButtonDown(0);
if ( mouseDown ) {
++Count;
}
}
}
Rxでの実装
class Hoge : MonoBehaviour {
public int Count { get; private set; }
public void Start() {
IObservable<Unit> mouseDown = gameObject.OnMouseDownAsObservable();
mouseDown.Subscribe( _ => ++Count );
}
}
Rxでの実装
class Hoge : MonoBehaviour {
public int Count { get; private set; }
public void Start() {
IObservable<Unit> mouseDown = gameObject.OnMouseDownAsObservable();
// ↑マウスが押された時にUnitが流れてくるメッセージストリームを取得
mouseDown.Subscribe( _ => ++Count );
}
}
Rxでの実装
class Hoge : MonoBehaviour {
public int Count { get; private set; }
public void Start() {
IObservable<Unit> mouseDown = gameObject.OnMouseDownAsObservable();
// ↑Unitとは何でもないものを表す(後々出てくるストリームの合成で型をあわせる為に必要)
mouseDown.Subscribe( _ => ++Count );
}
}
Rxでの実装
class Hoge : MonoBehaviour {
public int Count { get; private set; }
public void Start() {
IObservable<Unit> mouseDown = gameObject.OnMouseDownAsObservable();
// ↓イベントが流れてきたら処理を実行する
mouseDown.Subscribe( _ => ++Count );
}
}
例題A’
マウスを押しっぱなしにしている間、
一定間隔で数値をカウントアップさせる。
Rxではない実装
class Hoge : MonoBehaviour {
private DateTime nextCountUp = DateTime.Now;
private TimeSpan countUpIntervalSpan = TimeSpan.FromSeconds( 1 );
public void Update() {
bool mouseDown = Input.GetMouseButtonDown(0);
if ( mouseDown && nextCountUp <= DateTime.Now ) {
++Count;
nextCountUp = DateTime.Now + countUpIntervalSpan;
}
else if ( false == mouseDown ) { nextCountUp = DateTime.Now; }
}
}
Rxではない実装
class Hoge : MonoBehaviour {
private DateTime nextCountUp = DateTime.Now; // 次回カウントアップまでの秒数管理.
private TimeSpan countUpIntervalSpan = TimeSpan.FromSeconds( 1 );
public void Update() {
bool mouseDown = Input.GetMouseButtonDown(0);
if ( mouseDown && nextCountUp <= DateTime.Now ) {
++Count;
nextCountUp = DateTime.Now + countUpIntervalSpan;
}
else if ( false == mouseDown ) { nextCountUp = DateTime.Now; }
}
}
Rxではない実装
class Hoge : MonoBehaviour {
private DateTime nextCountUp = DateTime.Now;
private TimeSpan countUpIntervalSpan = TimeSpan.FromSeconds( 1 );
public void Update() {
bool mouseDown = Input.GetMouseButtonDown(0); // 押されているかどうかの判定.
if ( mouseDown && nextCountUp <= DateTime.Now ) {
++Count;
nextCountUp = DateTime.Now + countUpIntervalSpan;
}
else if ( false == mouseDown ) { nextCountUp = DateTime.Now; }
}
}
Rxではない実装
class Hoge : MonoBehaviour {
private DateTime nextCountUp = DateTime.Now;
private TimeSpan countUpIntervalSpan = TimeSpan.FromSeconds( 1 );
public void Update() {
bool mouseDown = Input.GetMouseButtonDown(0);
if ( mouseDown && nextCountUp <= DateTime.Now ) { // 間隔の制御.
++Count;
nextCountUp = DateTime.Now + countUpIntervalSpan;
}
else if ( false == mouseDown ) { nextCountUp = DateTime.Now; }
}
}
Rxではない実装
class Hoge : MonoBehaviour {
private DateTime nextCountUp = DateTime.Now;
private TimeSpan countUpIntervalSpan = TimeSpan.FromSeconds( 1 );
public void Update() {
bool mouseDown = Input.GetMouseButtonDown(0);
if ( mouseDown && nextCountUp <= DateTime.Now ) {
++Count; // 目的の処理.
nextCountUp = DateTime.Now + countUpIntervalSpan;
}
else if ( false == mouseDown ) { nextCountUp = DateTime.Now; }
}
}
Rxではない実装
class Hoge : MonoBehaviour {
private DateTime nextCountUp = DateTime.Now;
private TimeSpan countUpIntervalSpan = TimeSpan.FromSeconds( 1 );
public void Update() {
bool mouseDown = Input.GetMouseButtonDown(0);
if ( mouseDown && nextCountUp <= DateTime.Now ) {
++Count;
nextCountUp = DateTime.Now + countUpIntervalSpan; // 次のカウントアップ時間の予約.
}
else if ( false == mouseDown ) { nextCountUp = DateTime.Now; }
}
}
Rxではない実装
class Hoge : MonoBehaviour {
private DateTime nextCountUp = DateTime.Now;
private TimeSpan countUpIntervalSpan = TimeSpan.FromSeconds( 1 );
public void Update() {
bool mouseDown = Input.GetMouseButtonDown(0);
if ( mouseDown && nextCountUp <= DateTime.Now ) {
++Count;
nextCountUp = DateTime.Now + countUpIntervalSpan;
}
else if ( false == mouseDown ) { nextCountUp = DateTime.Now; }
} // ↑離された場合のカウントアップ予約解除処理
}
Rxでの実装
class Hoge : MonoBehaviour {
private TimeSpan countUpIntervalSpan = TimeSpan.FromSeconds( 1 );
public void Start() {
var mouseDown = gameObject.OnMouseDownAsObservable();
var mouseUp = gameObject.OnMouseUpAsObservable();
mouseDown
.SelectMany( _ => Observable.Interval( countUpIntervalSpan ) )
.TakeUntil( mouseUp ).RepeatUntilDestroy( this )
.Subscribe( _ => ++Count );
}
}
Rxでの実装
class Hoge : MonoBehaviour {
private TimeSpan countUpIntervalSpan = TimeSpan.FromSeconds( 1 );
public void Start() { // ↓マウスの状態ストリーム.
var mouseDown = gameObject.OnMouseDownAsObservable();
var mouseUp = gameObject.OnMouseUpAsObservable();
mouseDown
.SelectMany( _ => Observable.Interval( countUpIntervalSpan ) )
.TakeUntil( mouseUp ).RepeatUntilDestroy( this )
.Subscribe( _ => ++Count );
}
}
Rxでの実装
class Hoge : MonoBehaviour {
private TimeSpan countUpIntervalSpan = TimeSpan.FromSeconds( 1 );
public void Start() {
var mouseDown = gameObject.OnMouseDownAsObservable();
var mouseUp = gameObject.OnMouseUpAsObservable();
mouseDown // ←マウスが押されたら.
.SelectMany( _ => Observable.Interval( countUpIntervalSpan ) )
.TakeUntil( mouseUp ).RepeatUntilDestroy( this )
.Subscribe( _ => ++Count );
}
}
Rxでの実装
class Hoge : MonoBehaviour {
private TimeSpan countUpIntervalSpan = TimeSpan.FromSeconds( 1 );
public void Start() {
var mouseDown = gameObject.OnMouseDownAsObservable();
var mouseUp = gameObject.OnMouseUpAsObservable();
mouseDown
.SelectMany( _ => Observable.Interval( countUpIntervalSpan ) )
// ↑一定周期でメッセージが流れるストリームに切り換えて.
.TakeUntil( mouseUp ).RepeatUntilDestroy( this )
.Subscribe( _ => ++Count );
}
}
Rxでの実装
class Hoge : MonoBehaviour {
private TimeSpan countUpIntervalSpan = TimeSpan.FromSeconds( 1 );
public void Start() {
var mouseDown = gameObject.OnMouseDownAsObservable();
var mouseUp = gameObject.OnMouseUpAsObservable();
mouseDown
.SelectMany( _ => Observable.Interval( countUpIntervalSpan ) )
// ↓マウスが離されるまで.
.TakeUntil( mouseUp ).RepeatUntilDestroy( this )
.Subscribe( _ => ++Count );
}
}
Rxでの実装
class Hoge : MonoBehaviour {
private TimeSpan countUpIntervalSpan = TimeSpan.FromSeconds( 1 );
public void Start() {
var mouseDown = gameObject.OnMouseDownAsObservable();
var mouseUp = gameObject.OnMouseUpAsObservable();
mouseDown
.SelectMany( _ => Observable.Interval( countUpIntervalSpan ) )
// ↓マウスが離されたらもう一度押されるのを待つ.
.TakeUntil( mouseUp ).RepeatUntilDestroy( this )
.Subscribe( _ => ++Count );
}
}
Rxでの実装
class Hoge : MonoBehaviour {
private TimeSpan countUpIntervalSpan = TimeSpan.FromSeconds( 1 );
public void Start() {
var mouseDown = gameObject.OnMouseDownAsObservable();
var mouseUp = gameObject.OnMouseUpAsObservable();
mouseDown
.SelectMany( _ => Observable.Interval( countUpIntervalSpan ) )
.TakeUntil( mouseUp ).RepeatUntilDestroy( this )
.Subscribe( _ => ++Count ); // ←処理.
}
}
例題A’’
マウスを一定時間以上
押しっぱなしにしている間、
一定間隔で数値をカウントアップさせる。
Rxではない実装
class Hoge : MonoBehaviour {
private DateTime? beginCountUp = null;
private TimeSpan countUpHoldSpan = TimeSpan.FromSeconds( 1 );
public void Update() {
bool mouseDown = Input.GetMouseButtonDown(0);
if ( mouseDown ) {
if ( beginCountUp.HasValue ) {
if ( beginCountUp <= DateTime.Now ) { /* 一定間隔でカウントアップする処理 */ }
} else {
beginCountUp = DateTime.Now + countUpHoldSpan;
}
} else { beginCountUp = null; }
}
Rxではない実装
class Hoge : MonoBehaviour {
private DateTime? beginCountUp = null;
private TimeSpan countUpHoldSpan = TimeSpan.FromSeconds( 1 );
public void Update() {
bool mouseDown = Input.GetMouseButtonDown(0);
if ( mouseDown ) {
if ( beginCountUp.HasValue ) {
if ( beginCountUp <= DateTime.Now ) { /* 一定間隔でカウントアップする処理 */ }
} else {
beginCountUp = DateTime.Now + countUpHoldSpan;
}
} else { beginCountUp = null; }
}
Rxでの実装
class Hoge : MonoBehaviour {
private TimeSpan countUpHoldSpan = TimeSpan.FromSeconds( 1 );
public void Start() {
var mouseDown = gameObject.OnMouseDownAsObservable();
var mouseUp = gameObject.OnMouseUpAsObservable();
mouseDown.Delay( countUpHoldSpan )
.SelectMany( _ => Observable.Interval( TimeSpan.FromSeconds( 1 ) ) )
.TakeUntil( mouseUp ).RepeatUntilDestroy( this )
.Subscribe( _ => ++Count ); // ←処理.
}
}
Rxでの実装
class Hoge : MonoBehaviour {
private TimeSpan countUpHoldSpan = TimeSpan.FromSeconds( 1 );
public void Start() {
var mouseDown = gameObject.OnMouseDownAsObservable();
var mouseUp = gameObject.OnMouseUpAsObservable();
mouseDown.Delay( countUpHoldSpan )
.SelectMany( _ => Observable.Interval( TimeSpan.FromSeconds( 1 ) ) )
.TakeUntil( mouseUp ).RepeatUntilDestroy( this )
.Subscribe( _ => ++Count ); // ←処理.
}
}
Rxの利点
このように、Rxの方が時間を操作するための
オペレータが多数揃っているという点で優れています。
それ以外にもフィルタリング処理やデータの変換、
複数のストリームをマージすることができたり、
イベント処理と比べて処理を
1箇所にまとめて記述できるなど
その他の利点も多数存在します。
アジェンダ
・(Uni)Rxとは
・Rxの利点
・Rxの問題点
・UniRxの導入いろは
・デバッグ方法
・まとめ
Rxの問題点
問題点
動きが
予測しづらい
例えば
SkipUntilと
TakeUntil
SkipUntil/TakeUntilの動き
var s = new Subject<int>();
s.SkipUntil( x => ( 0 == ( x % 2 ) )
.TakeUntil( x => ( 0 != ( x % 2 ) )
.Subscribe( x => Debug.Log(x) );
s.OnNext( 1 );
s.OnNext( 2 );
s.OnNext( 3 );
s.OnNext( 4 );
結果 :
SkipUntil/TakeUntilの動き
結果 :
2で割り切れるまで読み飛ばす
var s = new Subject<int>();
s.SkipUntil( x => ( 0 == ( x % 2 ) )
.TakeUntil( x => ( 0 != ( x % 2 ) )
.Subscribe( x => Debug.Log(x) );
s.OnNext( 1 );
s.OnNext( 2 );
s.OnNext( 3 );
s.OnNext( 4 );
SkipUntil/TakeUntilの動き
結果 :
2で割り切れるまで読み飛ばす
2で割り切れる間は続ける
var s = new Subject<int>();
s.SkipUntil( x => ( 0 == ( x % 2 ) )
.TakeUntil( x => ( 0 != ( x % 2 ) )
.Subscribe( x => Debug.Log(x) );
s.OnNext( 1 );
s.OnNext( 2 );
s.OnNext( 3 );
s.OnNext( 4 );
SkipUntil/TakeUntilの動き
var s = new Subject<int>();
s.SkipUntil( x => ( 0 == ( x % 2 ) )
.TakeUntil( x => ( 0 != ( x % 2 ) )
.Subscribe( x => Debug.Log(x) );
s.OnNext( 1 );
s.OnNext( 2 );
s.OnNext( 3 );
s.OnNext( 4 );
結果 :
2で割り切れるまで読み飛ばす
2で割り切れる間は続ける
2だけが出力?
SkipUntil/TakeUntilの動き
var s = new Subject<int>();
s.SkipUntil( x => ( 0 == ( x % 2 ) )
.TakeUntil( x => ( 0 != ( x % 2 ) )
.Subscribe( x => Debug.Log(x) );
s.OnNext( 1 );
s.OnNext( 2 );
s.OnNext( 3 );
s.OnNext( 4 );
結果 :
出力なし
SkipUntil/TakeUntilの動き
結果 :
1が流れてきた時点で
TakeUntilの条件を満たしてしまい
ストリームが終了した
var s = new Subject<int>();
s.SkipUntil( x => ( 0 == ( x % 2 ) )
.TakeUntil( x => ( 0 != ( x % 2 ) )
.Subscribe( x => Debug.Log(x) );
s.OnNext( 1 );
s.OnNext( 2 );
s.OnNext( 3 );
s.OnNext( 4 );
SkipUntil/TakeUntilの動き
var s = new Subject<int>();
s.SkipUntil( x => ( 0 == ( x % 2 ) )
.TakeUntil( x => ( 0 != ( x % 2 ) )
.Subscribe( x => Debug.Log(x) );
s.OnNext( 1 );
s.OnNext( 2 );
s.OnNext( 3 );
s.OnNext( 4 );
理由 :
SkipUntilで待っている間も
TakeUntilの条件は
常にチェックされている。
解決策
慣れてください
Rxの各オペレータの動き
Rxにおける各オペレータは
ストリームの性質を定義しているに過ぎず、
LINQと同じ感覚で使っていると
思ったとおりに動かない。
Rxの各オペレータの動き
Rxにおける各オペレータは
ストリームの性質を定義しているに過ぎず、
LINQと同じ感覚で使っていると
思ったとおりに動かない。
⇒慣れるしかない
Rxの各オペレータの動き
Rxにおける各オペレータは
ストリームの性質を定義しているに過ぎず、
LINQと同じ感覚で使っていると
思ったとおりに動かない。
⇒慣れるしかない
http://rxmarbles.com/
問題点
購読し続ける事により
キャプチャされた
インスタンスが
解放されない
解決策
AddToという
オペレータを
使ってください
AddTo
public static IDisposable AddTo(this IDisposable disposable, GameObject
gameObject);
public static IDisposable AddTo(this IDisposable disposable, Component
gameObjectComponent)
public static IDisposable AddTo(this IDisposable disposable,
ICollection<IDisposable> container, GameObject gameObject)
public static IDisposable AddTo(this IDisposable disposable,
ICollection<IDisposable> container, Component gameObjectComponent)
public static T AddTo<T>(this T disposable, ICollection<IDisposable>
container)
AddTo
// OnDestroyで勝手に破棄
Observable...Subscribe().AddTo( this );
Observable...Subscribe().AddTo( gameObject );
// 参照を失った時やDispose()が呼ばれた時に破棄
var d = new CompositeDisposable();
Observable...Subscribe().AddTo( d );
問題点
オペレータ毎に
増えていく
メモリ使用量
解決策(?)
処理負荷との
トレードオフで検討
(GC...)
オペレータ実行時にObserverクラスが生成される。
小さなクラスが大量に生成される。 -> GC負荷が上がる。
欠点:メモリ使用量とGCのコスト
オペレータ実行時にObserverクラスが生成される。
小さなクラスが大量に生成される。 -> GC負荷が上がる。
UniRxの場合、専用のコンポーネントが生成される。
生成コストや上記と同じくGCの負荷が上がる。
欠点:メモリ使用量とGCのコスト
オペレータ実行時にObserverクラスが生成される。
小さなクラスが大量に生成される。 -> GC負荷が上がる。
UniRxの場合、専用のコンポーネントが生成される。
生成コストや上記と同じくGCの負荷が上がる。
不要なオブジェクトの参照を握り続けてしまう。(前述)
解放できない領域が残る可能性がある。 -> メモリリーク
欠点:メモリ使用量とGCのコスト
変数などに変更が加わった時だけなど
必要なときにだけ処理が実行される。
処理負荷が軽減されることを期待できる。
利点:処理負荷やバグの出難さ
変数などに変更が加わった時だけなど
必要なときにだけ処理が実行される。
処理負荷が軽減されることを期待できる。
メンバ変数などを保持する必要がなくなる。
変数の状態起因系のバグが出にくい。
利点:処理負荷やバグの出難さ
変数などに変更が加わった時だけなど
必要なときにだけ処理が実行される。
処理負荷が軽減されることを期待できる。
メンバ変数などを保持する必要がなくなる。
変数の状態起因系のバグが出にくい。
小さな関数の合成によりコーディング中のバグが出にくい。
関数型プログラミングの利点がそのまま利点に。
といっても副作用のある関数だとバグは出ます。
利点:処理負荷やバグの出難さ
問題点
とっつきにくい
解決策
慣れてください
正直、Rxはトライアンドエラーで
動作の感覚を身につけるしか
習熟する方法はないと思います。
問題点
学習コストが高い
解決策
慣れるための
環境づくり
先日のUniRx勉強会で話を聞いたところ、
LINQを知らない人の基準での学習コストは
概ね1ヶ月ほどとのことです。
また、LINQがわかるなら
もう少し短縮できるだろうとのことでした。
学習コスト
それでも
使わないとRxのコードも読めません。
そのため、
みんなでRxでコードを書こうという
チーム内での合意が必要です!
学習コスト
問題点
勉強方法
解決策
ググる
Rxについては
ReactiveExtensionsで検索すれば
解説が多数ヒットします。
UniRxについても
“UniRx”で検索すれば
(Google先生がUnixをお勧めしてくれるので)
解説が多数ヒットします。
強いて言えば
以下のサイトがお勧めです。
http://rxmarbles.com/
http://qiita.com/tags/unirx
https://unityuserj.slack.com/messages/unirx/
先日行われた
UniRx勉強会の資料
はじめてのUniRx
若輩エンジニアから見たUniRxを利用したゲーム開発
Interactive UI with UniRx
History & Practices for UniRx UniRxの歴史、
或いは開発(中)タイトルの用例と落とし穴の回避法
「ずいぶんとダサいライティングを使っているのね
〜UniRxを用いた物理ベースライティング制御〜
UniRx勉強会のまとめ
興味を持ったので
UniRxを使ってみたい
でもどこから
手を付けていいのか
わからない
ということで
アジェンダ
・(Uni)Rxとは
・Rxの利点と問題点
・UniRxの導入いろは
・デバッグ方法
・まとめ
UniRxの
導入いろは
AssetStoreからパッケージで落とす
https://www.assetstore.unity3d.com/jp/#!/content/17276
Githubからソースを落とす
https://github.com/neuecc/UniRx
UniRxをプロジェクトに追加
手の付け方
public event Action SomeEvent;
があった場合、
Observable.FromEvent(
h => SomeEvent += h, h => SomeEvent -= h
)
を行えばストリームに変換できます。
イベントをストリームに変換する
public delegate void SomeEvent();
public SomeEvent someEvent;
があった場合、
Observable.FromEvent<SomeEvent>(
h => ()=>h(), h => SomeEvent += h, h => SomeEvent -= h
) // デリゲートに変換
を行えばストリームに変換できます。
デリゲートをストリームに変換する
var s = new Subject<T>();
を定義して
s.OnNext(...);
で配信することができます。
s.OnCompleted();
でストリームの終了ができます。
Subjectでメッセージを配信
全てのストリームは
Subjectが起点だと思って問題無いです。
Subjectでメッセージを配信
IDisposable d =
IObservable<T>.Subscribe<T>(
Action<T> onNext,
Action<Exception> onError,
Action onCompleted
);
onNextのみなど各種パターンが用意されています。
配信されているメッセージを購読
Rxではない実装
private int? previousValue = null;
void Update() {
var value = 監視したい値;
if ( previousValue.HasValue && previousValue.Value != value ) {
/* 処理 */
}
previousValue = value;
}
値の監視
値の監視
Rxでの実装
component.ObserveEveryValueChanged( _ => 監視したい値 )
var rp = new ReactiveProperty<T>(初期値);
があれば
IObservable<T> rpAsObservable { get { return rp; } }
で配信することができます。
配信タイミングは rp.Value = 値; などで値が書き換わった時。
ReactiveProperty<T>
var rp = new ReactiveProperty<T>(初期値);
また、ストリームとして以外でも
rp.Value でその時点での値が取得できます。
ReactiveProperty<T>
private ReactiveProperty<T> ValueProperty;
public IObservable<T> ValueAsObservable {
get { return ValueProperty; }
}
public T Value {
get { return ValueProperty.Value; }
private set { ValueProperty.Value = value; }
}
は鉄板だと思います!ぜひスニペットに登録を!
ReactiveProperty<T>
ピンと来ない方はExcelなどのセルを
想像して頂けるとわかりやすいかと思います。
そのセルを更新すると他のセルも更新される、という感じです。
ReactiveProperty<T>
その他Bindingもどきなど活用法が多々ありますので
いろいろ調べて使ってみてください。
MV(R)P : Model View ReactiveProperty
という構造も推奨されています。
今回は割愛します。
ReactiveProperty<T>
ReactiveProperty<T>をSerializeFieldに指定しても
ジェネリック型であるため、Inspectorに表示されない。
しかし、ジェネリック型でなくせばその制限がなくなるため、
以下のように基本的な型が用意されている。
IntReactiveProperty LongReactiveProperty ByteReactiveProperty
FloatReactiveProperty DoubleReactiveProperty StringReactiveProperty
BoolReactiveProperty Vector2ReactiveProperty Vector3ReactiveProperty
Vector4ReactiveProperty ColorReactiveProperty RectReactiveProperty
AnimationCurveReactiveProperty BoundsReactiveProperty
QuaternionReactiveProperty
.*ReactiveProperty
List及びDictinaryのReactiveProperty版です。
ReactiveCollection/ReactiveDictionary
AddTo()でちらっと解説しましたが、
IDisposableをまとめて管理してくれるクラスです。
基本はGCされた時にDisposeする用途が多いですが、
Disposeを明示的にコールしたい時などに使用します。
繰り返し使用したい場合はDisposeではなく
Clearを使用するようにしましょう。
同系統のクラスはこちらに解説があります。
http://blog.xin9le.net/entry/2014/02/10/120619
CompositeDisposable
ストリームの再購読の方法として
Repeat()をよく見かけます。
しかし、これだと無限に
購読し続けるおそれがあります。
UniRxの場合は RepeatUntilDestroy() を
使用するようにしましょう。
Repeat()について
Unityではシングルスレッドの動作しかできませんが、
UniRxを使うことで別スレッドで計算などをさせることができます。
(ただし、私は使ったことがないため、紹介だけ・・・)
Observable.Start() : バックグラウンドで処理を実行
ObserveOn(Scheduler.ThreadPool) : 以降の処理を別スレッドで実行
ObserveOnMainThread() : メインスレッドに処理を戻す
別スレッド実行
uGUIやWWWなどのクラスをラップした
オペレータが標準で用意されています。
これにより、以下のような簡単なコードで目的が達成できます。
また、各種オペレータにより、タイムアウトやリトライも簡単に!
(ただし、これも使ったことないです・・・。)
// ボタン押下
Button.onClick.AsObservable().Subscribe()
// httpアクセス
ObservableWWW.Get()
uGUIやhttpなどのラッパー
RxにはHotやColdといった状態があります。
これについては別スライドができるくらいの
情報量がありますので、
解説されたQiitaページの紹介を。
RxのHotとColdについて
http://qiita.com/toRisouP/items/f6088963037bfda658d3
Hot/Cold
SelectやWhereなど、LINQでよく見るオペレータは
ひと通りあるイメージで問題ありません。
その他Rx独自のオペレータについては
以下のサイトなどをご活用ください。
http://rxmarbles.com/
https://msdn.microsoft.com/en-
us/library/system.reactive.linq.observable_methods(v=vs.103).
aspx
http://www.slideshare.net/okazuki0130/reactive-extensionsv01
その他ストリームに対するオペレータ
UniRxの作者様のブログ
株式会社グラニ 河合 宜文 様 @neuecc
http://neue.cc/category/programming/rx
その他
http://blog.xin9le.net/entry/rx-intro
http://qiita.com/toRisouP
その他お勧めな解説サイト
アジェンダ
・(Uni)Rxとは
・Rxの利点と問題点
・UniRxの導入いろは
・デバッグ方法
・まとめ
デバッグ方法
Doというオペレータを使用します。
s.Do( x => Debug.Log( x ) )
ストリームの途中の値(到達)を確認する
Finallyというオペレータを使用します。
s.TakeUntil(...)
.Finally( () => Debug.Log( “” ) )
.RepeatUntilDestroy()
Repeatしたのかどうかを確認する
ストリームという性質上できません。
ステップ実行
アジェンダ
・(Uni)Rxとは
・Rxの利点と問題点
・UniRxの導入いろは
・デバッグ方法
・まとめ
まとめ
多分皆さんが
(過去の私も)
思っているほど
難しくないです
なので
ぜひ導入してみてください!
質疑応答
ご静聴
ありがとう
ございました。

More Related Content

What's hot

History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法
History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法
History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法
Yoshifumi Kawai
 

What's hot (20)

【Unite Tokyo 2019】Unityだったら簡単!マルチプレイ用ゲームサーバ開発 ~実践編~
【Unite Tokyo 2019】Unityだったら簡単!マルチプレイ用ゲームサーバ開発 ~実践編~【Unite Tokyo 2019】Unityだったら簡単!マルチプレイ用ゲームサーバ開発 ~実践編~
【Unite Tokyo 2019】Unityだったら簡単!マルチプレイ用ゲームサーバ開発 ~実践編~
 
Unityではじめるオープンワールド制作 エンジニア編
Unityではじめるオープンワールド制作 エンジニア編Unityではじめるオープンワールド制作 エンジニア編
Unityではじめるオープンワールド制作 エンジニア編
 
Doozy UI 使おうぜ! #unity_lt
Doozy UI 使おうぜ! #unity_ltDoozy UI 使おうぜ! #unity_lt
Doozy UI 使おうぜ! #unity_lt
 
Unityでオンラインゲーム作った話
Unityでオンラインゲーム作った話Unityでオンラインゲーム作った話
Unityでオンラインゲーム作った話
 
Unity開発で使える設計の話+Zenjectの紹介
Unity開発で使える設計の話+Zenjectの紹介Unity開発で使える設計の話+Zenjectの紹介
Unity開発で使える設計の話+Zenjectの紹介
 
Unityでパフォーマンスの良いUIを作る為のTips
Unityでパフォーマンスの良いUIを作る為のTipsUnityでパフォーマンスの良いUIを作る為のTips
Unityでパフォーマンスの良いUIを作る為のTips
 
【Unity】 Behavior TreeでAIを作る
 【Unity】 Behavior TreeでAIを作る 【Unity】 Behavior TreeでAIを作る
【Unity】 Behavior TreeでAIを作る
 
コールバックと戦う話
コールバックと戦う話コールバックと戦う話
コールバックと戦う話
 
ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14ゲーム開発者のための C++11/C++14
ゲーム開発者のための C++11/C++14
 
Observableで非同期処理
Observableで非同期処理Observableで非同期処理
Observableで非同期処理
 
【Unite 2018 Tokyo】60fpsのその先へ!スマホの物量限界に挑んだSTG「アカとブルー」の開発設計
【Unite 2018 Tokyo】60fpsのその先へ!スマホの物量限界に挑んだSTG「アカとブルー」の開発設計【Unite 2018 Tokyo】60fpsのその先へ!スマホの物量限界に挑んだSTG「アカとブルー」の開発設計
【Unite 2018 Tokyo】60fpsのその先へ!スマホの物量限界に挑んだSTG「アカとブルー」の開発設計
 
インタフェース完全に理解した
インタフェース完全に理解したインタフェース完全に理解した
インタフェース完全に理解した
 
C# ゲームプログラミングはホントにメモリのことに無頓着でいいの?
C# ゲームプログラミングはホントにメモリのことに無頓着でいいの?C# ゲームプログラミングはホントにメモリのことに無頓着でいいの?
C# ゲームプログラミングはホントにメモリのことに無頓着でいいの?
 
Unity 2018-2019を見据えたDeNAのUnity開発のこれから [DeNA TechCon 2019]
Unity 2018-2019を見据えたDeNAのUnity開発のこれから [DeNA TechCon 2019]Unity 2018-2019を見据えたDeNAのUnity開発のこれから [DeNA TechCon 2019]
Unity 2018-2019を見据えたDeNAのUnity開発のこれから [DeNA TechCon 2019]
 
Unityで始めるバージョン管理 Git LFS 入門編
Unityで始めるバージョン管理 Git LFS 入門編Unityで始めるバージョン管理 Git LFS 入門編
Unityで始めるバージョン管理 Git LFS 入門編
 
History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法
History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法
History & Practices for UniRx UniRxの歴史、或いは開発(中)タイトルの用例と落とし穴の回避法
 
【CEDEC2017】Unityを使ったNintendo Switch™向けのタイトル開発・移植テクニック!!
【CEDEC2017】Unityを使ったNintendo Switch™向けのタイトル開発・移植テクニック!!【CEDEC2017】Unityを使ったNintendo Switch™向けのタイトル開発・移植テクニック!!
【CEDEC2017】Unityを使ったNintendo Switch™向けのタイトル開発・移植テクニック!!
 
UniRx の1歩目
UniRx の1歩目UniRx の1歩目
UniRx の1歩目
 
【Unity道場スペシャル 2017京都】最適化をする前に覚えておきたい技術
【Unity道場スペシャル 2017京都】最適化をする前に覚えておきたい技術【Unity道場スペシャル 2017京都】最適化をする前に覚えておきたい技術
【Unity道場スペシャル 2017京都】最適化をする前に覚えておきたい技術
 
中級グラフィックス入門~シャドウマッピング総まとめ~
中級グラフィックス入門~シャドウマッピング総まとめ~中級グラフィックス入門~シャドウマッピング総まとめ~
中級グラフィックス入門~シャドウマッピング総まとめ~
 

Similar to UniRxことはじめ

デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる
デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくるデジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる
デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる
Atsushi Tadokoro
 
メディア・アートII 第2回 openFrameworks基礎 配列、くりかえし、乱数 ベクトルを使用したアニメーション
メディア・アートII  第2回 openFrameworks基礎 配列、くりかえし、乱数 ベクトルを使用したアニメーションメディア・アートII  第2回 openFrameworks基礎 配列、くりかえし、乱数 ベクトルを使用したアニメーション
メディア・アートII 第2回 openFrameworks基礎 配列、くりかえし、乱数 ベクトルを使用したアニメーション
Atsushi Tadokoro
 
Media Art II 2013 第7回 : openFrameworks 3Dグラフィクス、OpenGL
Media Art II 2013 第7回 : openFrameworks 3Dグラフィクス、OpenGLMedia Art II 2013 第7回 : openFrameworks 3Dグラフィクス、OpenGL
Media Art II 2013 第7回 : openFrameworks 3Dグラフィクス、OpenGL
Atsushi Tadokoro
 
Boost9 session
Boost9 sessionBoost9 session
Boost9 session
freedom404
 
Continuation with Boost.Context
Continuation with Boost.ContextContinuation with Boost.Context
Continuation with Boost.Context
Akira Takahashi
 

Similar to UniRxことはじめ (20)

タイマー
タイマータイマー
タイマー
 
デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる
デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくるデジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる
デジタルアートセミナー#2 openFrameworksで学ぶ、 クリエイティブ・コーディング Session 2: 構造をつくる
 
メディア・アートII 第2回 openFrameworks基礎 配列、くりかえし、乱数 ベクトルを使用したアニメーション
メディア・アートII  第2回 openFrameworks基礎 配列、くりかえし、乱数 ベクトルを使用したアニメーションメディア・アートII  第2回 openFrameworks基礎 配列、くりかえし、乱数 ベクトルを使用したアニメーション
メディア・アートII 第2回 openFrameworks基礎 配列、くりかえし、乱数 ベクトルを使用したアニメーション
 
コルーチンの使い方
コルーチンの使い方コルーチンの使い方
コルーチンの使い方
 
Java初心者勉強会(2015/08/07)資料
Java初心者勉強会(2015/08/07)資料Java初心者勉強会(2015/08/07)資料
Java初心者勉強会(2015/08/07)資料
 
Media Art II 2013 第7回 : openFrameworks 3Dグラフィクス、OpenGL
Media Art II 2013 第7回 : openFrameworks 3Dグラフィクス、OpenGLMedia Art II 2013 第7回 : openFrameworks 3Dグラフィクス、OpenGL
Media Art II 2013 第7回 : openFrameworks 3Dグラフィクス、OpenGL
 
About Jobs
About JobsAbout Jobs
About Jobs
 
Leap Motion - 1st Review
Leap Motion - 1st ReviewLeap Motion - 1st Review
Leap Motion - 1st Review
 
板ポリだけで めちゃカッコいい グラフィックスを出す!
板ポリだけで めちゃカッコいい グラフィックスを出す!板ポリだけで めちゃカッコいい グラフィックスを出す!
板ポリだけで めちゃカッコいい グラフィックスを出す!
 
Boost9 session
Boost9 sessionBoost9 session
Boost9 session
 
UnityとBlenderハンズオン第2章
UnityとBlenderハンズオン第2章UnityとBlenderハンズオン第2章
UnityとBlenderハンズオン第2章
 
Unit testing JavaScript with JUnit/JavaFX
Unit testing JavaScript with JUnit/JavaFXUnit testing JavaScript with JUnit/JavaFX
Unit testing JavaScript with JUnit/JavaFX
 
react勉強会 #4
react勉強会 #4react勉強会 #4
react勉強会 #4
 
この辺でXamarin導入による 効果と限界をしっかり把握してみよう MVP Community Camp 2015
この辺でXamarin導入による 効果と限界をしっかり把握してみよう  MVP Community Camp 2015 この辺でXamarin導入による 効果と限界をしっかり把握してみよう  MVP Community Camp 2015
この辺でXamarin導入による 効果と限界をしっかり把握してみよう MVP Community Camp 2015
 
Continuation with Boost.Context
Continuation with Boost.ContextContinuation with Boost.Context
Continuation with Boost.Context
 
Arctic.js
Arctic.jsArctic.js
Arctic.js
 
Implementation patterns
Implementation patternsImplementation patterns
Implementation patterns
 
Android gameprogramming
Android gameprogrammingAndroid gameprogramming
Android gameprogramming
 
enchant.js勉強会
enchant.js勉強会enchant.js勉強会
enchant.js勉強会
 
Why Reactive Matters #ScalaMatsuri
Why Reactive Matters #ScalaMatsuriWhy Reactive Matters #ScalaMatsuri
Why Reactive Matters #ScalaMatsuri
 

Recently uploaded

ビジュアルプログラミングIotLT17-オープンソース化されたビジュアルプログラミング環境Noodlの紹介
ビジュアルプログラミングIotLT17-オープンソース化されたビジュアルプログラミング環境Noodlの紹介ビジュアルプログラミングIotLT17-オープンソース化されたビジュアルプログラミング環境Noodlの紹介
ビジュアルプログラミングIotLT17-オープンソース化されたビジュアルプログラミング環境Noodlの紹介
miyp
 

Recently uploaded (8)

人的資本経営のための地理情報インテリジェンス 作業パターン分析と心身状態把握に関する実証事例
人的資本経営のための地理情報インテリジェンス 作業パターン分析と心身状態把握に関する実証事例人的資本経営のための地理情報インテリジェンス 作業パターン分析と心身状態把握に関する実証事例
人的資本経営のための地理情報インテリジェンス 作業パターン分析と心身状態把握に関する実証事例
 
【登壇資料】スタートアップCTO経験からキャリアについて再考する CTO・VPoEに聞く by DIGGLE CTO 水上
【登壇資料】スタートアップCTO経験からキャリアについて再考する  CTO・VPoEに聞く by DIGGLE CTO 水上【登壇資料】スタートアップCTO経験からキャリアについて再考する  CTO・VPoEに聞く by DIGGLE CTO 水上
【登壇資料】スタートアップCTO経験からキャリアについて再考する CTO・VPoEに聞く by DIGGLE CTO 水上
 
本の感想共有会「データモデリングでドメインを駆動する」本が突きつける我々の課題について
本の感想共有会「データモデリングでドメインを駆動する」本が突きつける我々の課題について本の感想共有会「データモデリングでドメインを駆動する」本が突きつける我々の課題について
本の感想共有会「データモデリングでドメインを駆動する」本が突きつける我々の課題について
 
ビジュアルプログラミングIotLT17-オープンソース化されたビジュアルプログラミング環境Noodlの紹介
ビジュアルプログラミングIotLT17-オープンソース化されたビジュアルプログラミング環境Noodlの紹介ビジュアルプログラミングIotLT17-オープンソース化されたビジュアルプログラミング環境Noodlの紹介
ビジュアルプログラミングIotLT17-オープンソース化されたビジュアルプログラミング環境Noodlの紹介
 
エンジニアのセルフブランディングと技術情報発信の重要性 テクニカルライターになろう 講演資料
エンジニアのセルフブランディングと技術情報発信の重要性 テクニカルライターになろう 講演資料エンジニアのセルフブランディングと技術情報発信の重要性 テクニカルライターになろう 講演資料
エンジニアのセルフブランディングと技術情報発信の重要性 テクニカルライターになろう 講演資料
 
Linuxサーバー構築 学習のポイントと環境構築 OSC2024名古屋 セミナー資料
Linuxサーバー構築 学習のポイントと環境構築 OSC2024名古屋 セミナー資料Linuxサーバー構築 学習のポイントと環境構築 OSC2024名古屋 セミナー資料
Linuxサーバー構築 学習のポイントと環境構築 OSC2024名古屋 セミナー資料
 
Compute Units/Budget最適化 - Solana Developer Hub Online 6 #SolDevHub
Compute Units/Budget最適化 - Solana Developer Hub Online 6 #SolDevHubCompute Units/Budget最適化 - Solana Developer Hub Online 6 #SolDevHub
Compute Units/Budget最適化 - Solana Developer Hub Online 6 #SolDevHub
 
今さら聞けない人のためのDevOps超入門 OSC2024名古屋 セミナー資料
今さら聞けない人のためのDevOps超入門 OSC2024名古屋  セミナー資料今さら聞けない人のためのDevOps超入門 OSC2024名古屋  セミナー資料
今さら聞けない人のためのDevOps超入門 OSC2024名古屋 セミナー資料
 

UniRxことはじめ

Editor's Notes

  1. ご覧のように様々な言語でサポートされています
  2. マウスの状態を取得して、カウントアップ
  3. メッセージストリームを取得 Unitについては次のページ
  4. コメントアウト部分に先ほどまでの処理が入ります。 これだけの追加実装が必要です。
  5. Delayというオペレータだけで実現可能です。
  6. Subjectというものがありますが、 これはメッセージを流すものです。 詳しくは後で説明するので 一旦そういうものとして認識しておいてください。
  7. 1,2,3,4と流した時に2だけが出力されるかとおもいきや・・・
  8. 関数型云々については
  9. 関数型云々については
  10. 関数型云々については宗教戦争になるので 納得出来ない方は流していただけるとありがたいです。
  11. ここでは細かい構文については触れません。 細かい構文については別途ググってください。
  12. Rx以外でも使えます。