UniRxクックブックてきな
今までに書いてきたよくあるRxのパターンを書いてく
- 連打対策.
class HogeController : Monobehaviour{ [SerializeField] Button btn; void do(){ Debug.Log("てすてすてす"); } void Awake(){ btn.OnClick.AsObservable() .ThrottleFirst(TimeSpan.FromSeconds(1)) .Subscribe(_ => do()).AddTo(this); } }
class RootHoge: MonoBehaviour{ [SerializeField] ChildHoge[] childrenComponent; void Awake(){ childrenComponent.Select(child => child.OnClicked).Merge().Subscribe(_ => { // いずれかの子供のClickStreamが発行された }).AddTo(this); } } class ChildHoge : MonoBehaviour{ [SerializeField] UIButton btn; public IObservable<Unit> OnClicked{ get; private set; } void Awake(){ OnClicked = btn.OnClick.AsObservable(); } }
- スタミナの回復時間などで前後時間を比較した計算する
例えばゲームのスタミナの回復時間を表示する箇所。 次の最大回復時間をサーバーから受け取って、現在時刻と比較するのが一般的だと思う。 ちょっと拡張して、次の回復までの時間、最大までの時間、現在の時間をRxで計算してみた
DateTime GetCurrentTime(){ // なんか return DateTime.Now; } // 初期化済 ReadOnlyReactiveProperty<int> TimeToMax; ReactiveProperty<int> timeToMax; ReactiveProperty<int> present; ReadOnlyReactiveProperty<int> Present; ReactiveProperty<int> intervalTime; ReadOnlyReactiveProperty<int> IntervalTime; ReactiveProperty<int> maxPoint; ReadOnlyReactiveProperty NextPointRecoverTime; // 通信するたびに最大回復までの時刻が更新される void Init(int timeToMax, int presentTime, int intervalTime){ //最大までの時間(秒) TimeToMax = timeToMax.Select(ttm => Observable.Timer(TimeSpan.FromSeconds(0),TimeSpan.FromSeconds(1)) .Select(_ => GetCurrentTime()).Buffer(2, 1) .Select(buf => (buf[1] - buf[0]).TotalSeconds) .Scan((double)0, (prev, current) => prev + current) .DistinctUntilChanged() .StartWith(0) .Select(t => Mathf.RoundToInt(t) ).Switch() .ToReadonlyReactiveProperty(); // 現在のスタミナ値 Present = present .CombineLatest(TimeToMax.Select(sec => Mathf.FloorToInt((TimeToMax.Select(sec => Mathf.FloorToInt(MaxPoint.Value - (float)sec / (float)Interval.Value)), (present, max) => Mathf.Max(p1, p2)) .DistinctUntilChanged() .ToReadOnlyReactiveProperty(); NextPointRecoverTime = this.TimeToMax.Select(sec => IntervalTime.Value == 0 ? 0 : sec % Interval.Value).ToReadOnlyReactiveProperty(); this.maxPoint.Value = maxPoint; this.interval.Value = interval; this.timeToMax.Value = timeToMax; }
- ストリームをmergeするけど、Streamごとに違う処理をはさみたい.
yes おされたときとno押された時に違う処理をした後に共通処理したい。(FinallyはOnError時にも引っかかってしまうのでそれでは困るケース)
HogePopup popup; popup.OnYesClicked.SelectMany(_ => API.PostYesData().Select(_ => UniRx.Unit)) .Merge(popup.OnNoClicked.SelectMany(_ => API.PostNo().Select(_ => UniRx.Unit)) .Subscribe(_ => {// 共通処理}) .AddTo(this);
- Switchする
たとえば、自動ページングするリストビューなど子供の要素数が変化するもの。 子供要素が変化が起こるたびにクリックストリームを更新したい
ReactiveCollection<HogeComponent> collection; // 子供要素が変化するたびにきちんとcollectionを同期する処理がどっかに実装されてる void Awake(){ collection = new RactiveCollection<HogeComponent>(); // hotにしたいかな var stream = collection.OnCountChanged().Select(_ => collection.Value.OnClicked).Switch().Publish(); stream.Connect(); stream.Subscribe(_ => { // なんか }); }