LoginSignup
36
24

More than 5 years have passed since last update.

UniRxのシンプルなサンプル その6(購読の停止)

Last updated at Posted at 2015-05-03

UniRxのシンプルなサンプルの取扱説明書
前(Buttonが押されたら動くGameObjet)
次(完了の通知)

購読の停止

以下のコードを見てください

DeadUpdate
using UnityEngine;
using System.Collections;
using UniRx;
using System;

public class DeadUpdate : Base {

    // Use this for initialization
    void Start () {

        gameObject.transform.position = new Vector2(0, 1f);

        //5秒後にgameObjectが死ぬ
        Observable.Timer(TimeSpan.FromSeconds(5))
           .Subscribe(_ => Destroy(gameObject));

        //0.5秒ごとに0.05右に移動
        Observable.Interval(TimeSpan.FromMilliseconds(500))
            .Subscribe(l => Move(0.5f, 0));
    }

    private void Move(float x, float y)
    {
        gameObject.transform.position = new Vector2(
            gameObject.transform.position.x + x, 
            gameObject.transform.position.y + y
        );
    }
}

このコードは5秒後にgameObjectが破棄されるまで0.5秒毎にカクカクと右に動き続けることを想定したコードです。

しかし、このコードは5秒後にgameObjectの破棄と同時に例外を吐いてしまいます。

Observable.Interval(TimeSpan time)timeごとに値をプッシュし続ける登録先です。
Observable.Timer(TimeSpan time)timeの後に1回だけ値をプッシュしてくれる登録先です。
それぞれ詳しくはUniRxのシンプルなサンプル その9(TimerとInterval 一定時間後に実行)を参照してください。

こんなかんじです。
スクリーンショット 2015-05-03 18.05.08.png

これの何が悪いかというとObservable.Interval(TimeSpan.FromMilliseconds(500)).Subscribe(l => Move(0.5f, 0));で行った登録がgameObjectが破棄された後も生き残っていてMoveを呼びだしちゃってるんですよね。
これはSubscribeで行った登録の登録解除(購読の停止とかいいます)をちゃんとしなければいけないよということです。
なので、この問題の解消をします。

準備

かなりシンプルに1個だけSafeUpdateというものをくっつけて作ります。
スクリーンショット 2015-05-03 17.38.13.png

AddTo

一番簡単な方法は以下のコードになります。

SafeAddTo
using UnityEngine;
using System.Collections;
using UniRx;
using System;

public class SafeUpdate : Base
{

    // Use this for initialization
    void Start () {

        gameObject.transform.position = new Vector2(0, 1f);

        //5秒後にgameObjectが死ぬ
        Observable.Timer(TimeSpan.FromSeconds(5))
            .Subscribe(_ => Destroy(gameObject));

        //0.5秒ごとに0.05右に移動
        Observable.Interval(TimeSpan.FromMilliseconds(500))
            .Subscribe(l => Move(0.1f, 0))
            .AddTo(this);//これを消すと登録が解除できず例外
    }
}

このようにSubscribeの後に.AddTo(Component c);cが破棄されたら一緒に購読停止してくれます。
これが一番簡単な方法ですね。

TakeUntilDestroy

更にTakeUnitilDestroyとかTakeUntilDisableとかもあります。

SafeUpdate
using UnityEngine;
using System.Collections;
using UniRx;
using System;

public class SafeUpdate : Base
{

    // Use this for initialization
    void Start () {

        gameObject.transform.position = new Vector2(0, 1f);

        //5秒後にgameObjectが死ぬ
        Observable.Timer(TimeSpan.FromSeconds(5))
            .Subscribe(_ => Destroy(gameObject));

        //0.5秒ごとに0.05右に移動
        Observable.Interval(TimeSpan.FromMilliseconds(500))
            .TakeUntilDestroy(this)//これを消すと例外
            .Subscribe(l => Move(0.1f, 0));
    }
}

TakeUntilDestroy(this)はthisが破棄されたらプッシュをやめます。

ちなみにですが後で説明する予定ですが、AddToではDispose()されるだけなのに対し、TakeUntilDestroy等ではOnCompletedというプッシュの終了が通知されることになるという違いがあります。

購読の停止(手動)

実はSubscribeの戻り値はIDisposableです。
これをDisposeすると購読が停止されます。

なので手動での削除はこんなコードになります。

SafeUpdate
using UnityEngine;
using System.Collections;
using UniRx;
using System;

public class SafeUpdate : Base
{

    // Use this for initialization
    void Start () {

        gameObject.transform.position = new Vector2(0, 1f);

        IDisposable mover =  Observable.Interval(TimeSpan.FromMilliseconds(500))
            .TakeUntilDestroy(this)
            .Subscribe(l => Move(0.1f, 0));

        //5秒後にgameObjectが死ぬ
        Observable.Timer(TimeSpan.FromSeconds(5)).Subscribe(_ => 
        {
            mover.Dispose();//moverを破棄して購読停止
            Destroy(gameObject);
        });
    }
}


削除されることが想定されているようなgameObjectを扱うときは登録先とか自分自身の寿命を考えるといいと思います。
ていうか基本AddToするといいと思います。

今までのサンプルのthis.UpdateAsObservable()this自身がオブザーバーだったので削除されても問題なく正常にストップします。

実行結果

ちゃんと消えたのにエラー出ませんやったー!
スクリーンショット 2015-05-03 17.48.18.png

36
24
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
36
24