トマシープが学ぶ

Unity/VR/AR/デザイン好きのミーハー 記事内容は自分用のメモです

UniRxをまなぶ

UniRxについて学んでいきます。

www.slideshare.net

qiita.com

この2つの資料および先輩に聞きながら書いています~

ごちゃごちゃ。自分用メモです。信用しないで

概要

Subject 主題

Observable 観察可能な(subject)

Observer 観察者・・・ObservableなSubjectの変化などを観察してメッセージを発する

Subscribe 購読・・・観察者が発したメッセージを購読(受け取る)する。

 

観察したいものを(subject)を定義する。

Observerがそのsubjectの変化や終わりを観察してメッセージを発する。

あらかじめSubjectをSubscribe(購読)したひとは、なにかあったらメッセージを受け取る。

受け取った後の処理も書いておく。

SubjectのObserver(観察者)が観察するのは変化だけじゃなくて観察した処理がおわったときなどもあるけど、ここでは変化とだけ書く。

概要+コード

・定義(Subject

観察したいものを(subject)を定義する。

public Subject<int> m_OnValueChange = new Subject<int>();

intのところは送りたいデータの型

・発行

メッセージを発したい場所、送るタイミングで名前.OnNext()などを書く

m_OnValueChange.OnNext(xxxx);

・購読(Subscribe

subjectの購読受信時のふるまいを別のスクリプトのstart()などに書く

SendScriptA.m_OnValueChange.Subscribe( x =>  Hoge()).AddTo(this);

受け取ったらHoge()を呼ぶなど。

 

 

実行してOnNextが呼ばれると、Subscribeが呼ばれて、その中のHoge()が動く。

書き方コピペ用 

<<送る側(発行)スクリプト>>

SendScriptA.cs

using UniRx;
using System;

private
Subject<Unit> m_OnValueChange = new Subject<Unit>(); public IObservable<Unit> OnValueChange { get { return m_OnValueChange; } } ///送るタイミングで   m_OnValueChange.OnNext(Unit.Default);

 

<<購読スクリプト>>

ObserverScript.cs

using UniRx;
using System;
	void Start () {
        SendScriptA.OnValueChange.Subscribe( _ => { Hoge(); }).AddTo(this);
    }

 

ストリーム

一連の流れのこと

qiita.com

メッセージを発行

メッセージを流す

subscribeする

処理する

Subject

SubjectはIObserverIObservableの2つの機能を継承したクラス。

IObserverはメッセージを流したりするほう。OnNextとかができる。

IObservableは購読。Subscribeができる

private Subject<int> m_OnValueChange = new Subject<int>();
public IObservable<int> OnValueChange { get { return m_OnValueChange; } }

 subjectそのものはpublicにしないで、Subjectの2つある機能のうちのIObservableだけをpublicにする。

すると購読する側のスクリプトではSubscribeしかできない。OnNextとかの

上の行をpublicにするだけでも送ることはできるが、OnNextとかのメッセージ発信機能も使えてしまって設計上よくない。

上の<int>の部分は送るものの型。何も送らない場合はUnit

 

複数送りたいとき

同時にfloatを複数送りたいときSubject<float,float>ってやると怒られた。

考えられる修正で出てきたISubject<float,float>にしたらそこのエラーは消えた。

でも違うみたい。

https://qiita.com/toRisouP/items/2f1643e344c741dd94f8

できないからクラス型を自分で作ればいいそう。

観察者・発行・メッセージ出す側

メッセージ

OnNext・・・メッセージの変化通知

OnError・・・ストリームの停止andエラー通知

OnCompleted・・・ストリームの停止and完了通知

qiita.com

OnError、OnCompletedを受け取ったら、それ以降メッセージを受け取らない。

カッコの中身

メッセージには数字とか゚変数とか゚文字とか関数とか゚を添えることができる。

subject.OnNext("Enemy");

 

何も添えずに、自分が呼ばれたことだけを知らせたい場合は

m_OnTabletActive.OnNext(Unit.Default);

 

そのほかは、宣言するときに指定した型

m_OnTabletActive.OnNext(.中身);

購読

subjectの購読受信時のふるまいを別のスクリプトのstart()などに書く

SendScriptA.m_OnValueChange.Subscribe( x =>  Hoge()).AddTo(this);

受け取ったらHoge()を呼ぶ。

=>の左側(引数)

xの部分は何の文字でもいい。OnNextで送ったものがxに入ってHoge()の引数に渡される。

Unit.Defaultのように何も送らなくてもいいけどxは必要。中身は空

逆に複数もらう場合は

Subscribe( (a,b) =>  Hoge())

のようにかっこで囲む。

=>の右側(処理)

書こうと思えば処理はいっぱいかける。

長くなる時はメソッドにしたほうがいいよ。

2行以上になるときは

Subscribe( (a,b) => {  ~~~~~~

~~~~})

のように中カッコ

 

OnError、OnCompletedなどを発するときは

Subscribe(
x => Debug.Log("OnNextの時の処理"), //OnNext
ex => Debug.Log("OnErrorの時の処理") //OnError
);

ラムダ式

このSubscribe()の中身はラムダ式という書き方をしているらしい。

qiita.com

メソッドにせず、引数を与え処理を書く場合の書き方のこと

オペレーター

購読時に受け取り条件を付けたり、受け取ったものを料理したりできる。

m_ReactiveProperty.OnValueChanged
.SkipLatestValueOnSubscribe()
.Where(x => x % 2 == 0)
.Select(x => x * x)
.Subscribe*1;

そのほかの使い方はこちらの記事にまとまっている

 

qiita.com

uGUI

もとからボタン押下などの発行イベントが用意されているので、購読側だけ書けばいい。

m_Button.onClick.AsObservable().Subscribe( ( _ ) => Hoge());

qiita.com

値の変化 ?

InputField.OnValueChangedAsObservable.Subscribe

qiita.com

qiita.com

SubscribeしたらUpdate

qiita.com

using UniRx.Triggers;

    tomatoDestroy.OnEat.Subscribe(_ => { Eat(); }).AddTo(this);
        startButton.onClick.AsObservable().Subscribe((_) => {
            textUI.SetActive(true);
            this.UpdateAsObservable().Subscribe( _ =>
            {
                TomatoMake();
                Timer();
               
            });
        });

Updateを止めるには


onCompletedを使えないとき。ボタンからの発信なので自分でonCompletedの前の部分を定義できない。。。

disposableを使う。

qiita.com

var disposable = new SingleAssignmentDisposable();

disposable.Disposable = this.UpdateAsObservable().Subscribe(x => {

if (止まる判定) {

disposable.Dispose();

}

}

        var disposable = new SingleAssignmentDisposable();     

        startButton.onClick.AsObservable().Subscribe((_) => {
 
            disposable.Disposable = this.UpdateAsObservable().Subscribe(x =>
            {
                TomatoMake();
                Timer();
                if (isGameStart == false)
                {
                    disposable.Dispose();
                }
            });
        });

ReactiveProperty

変数を渡せるSubject

    private ReactiveProperty<int> m_OnValueChange = new ReactiveProperty<int>();
    public IReadOnlyReactiveProperty<int> OnValueChange { get { return m_OnValueChange; } }

///送る箇所で
  m_OnValueChange.Value = 1;

購読側は変わらない

UIの値の変更通知に使うことが多い?

nobollel-tech.hatenablog.com

N秒ごとにメソッドを実行する

light11.hatenadiary.com

Observable.Interval(TimeSpan.FromSeconds(STATE_UPDATE_INTERVAL)).Subscribe(_ => UpdateStatus());

FromSeconds()の中はTimeSpanという型。

秒にするには TimeSpan.FromSeconds(10)

dobon.net

結局いつ使うのか

UniRXは結局いつ使うのか。

いままでUpdate()の中で、「もしAがactiveになったらXXする。」みたいに監視する処理を書いてた。でもUpdate()でずっと監視しているのは処理しすぎでよくない。

UniRxでイベントを発信させてその時だけ受け取るようにする。

 

あとeventに例えられているけど、Eventを使ったことないから分からない。

最後に

完全に理解した

f:id:bibinbaleo:20190613214442p:plain

 

*1:x) => Debug.Log(x