たくあんポリポリ

勉強したことを載せていきます。最近、技術系の記事はZennに書いています。(https://zenn.dev/chittai)

以前つくったゲームの処理の一部をUniRxで書き直してみた

前に作ったゲームをUniRxで一部処理を書き換えてみました。自分がどんな処理をUniRxで書き換えたのか記載します。

c-taquna.hatenablog.com

使用した環境は以下

  • Unity 2018.1.3f1
  • UniRx 6.1.2

今回やってみたこと

今まで、手続きてきな処理で実装していましたが、UniRxを使用すると諸々きれいにかけると聞いて、UniRxを使って書き換えを行ってみました。

カウントダウンの処理を書き換え

qiita.com
やりたいことがほぼ↑に書いてあることだったので、参考にしました。
ゲームをしていると、カウントダウンタイマーが欲しくなってくることが多いと思います。今までだと、だいたいコルーチンで処理を書いていましたが、これをUniRxで書き直すと

IEnumerator PlayTimeCountCoroutine()
    {
        while (_PlayTime >= 0)
        {
            yield return new WaitForSeconds(1);
            _PlayTime -= 1;
        }
    }
    private IObservable<int> CreateCountDownObservable(int CountTime)
    {
        return Observable
                .Timer(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(1))
                .Select(x => (int)(CountTime - x))
                .TakeWhile(x => x > 0);
    }

こうなりました。Timerで秒数を指定して、Selectで値を計算し、TakeWhileでその値が0より大きい間は繰り返し処理をさせる書き方です

呼び出しは下記の様に行っています。

    ///<summury>
    ///開始までのカウントダウン
    ///</summury>
    public IObservable<int> GameStartCountDownObservable { get; private set; }
    var startConnectableObservable = CreateCountDownObservable(3).Publish();

カウントダウン処理は、開始までの時間とプレイ中の時間など同じストリームを複数回呼ぶことになるので、PublishでHotに変換しています。

ゲーム内の 処理の直列化

今までだと、ゲームを開始・プレイ中・終了を管理用変数を用意して管理していました。ただ、今回はそれをなくそうという目的でUniRxで書き換えてみました。特にポイントとしては、開始→プレイ中→終了と状態が遷移していくので処理が直列になることです。下記が今までの状態です。

      switch (_Playstatus)
        {
            case PLAY_START:
            //プレイ開始時の処理。主に開始までのカウントダウンを実行。今回だと3sカウントしてその後実行してます。
            break;

            case PLAY:
            //プレイ中の処理。ここではプレイ時間をカウントしたり、クリア時の処理・タイムアップ時の処理を記載しています。
            break;

            case PLAY_END:
            //プレイ終了時の処理。ここでは、プレイ終了したらゲーム→メニューにシーン遷移するため、色々な変数を初期化しています
            break;

今回は例として、スタート時点の処理を記載します。

        ///<Summary>
        ///3s のカウントダウンのあとに、ゲームを開始する
        ///</Summary>
        GameStartCountDownObservable
            .Take(4)
            .Subscribe(time => m_Countdown.text = time.ToString(), () =>
            {
                m_Countdown.text = "PLAY START";
                _Timer = 0;
                _Playstatus = PLAY;
                displayConnectableObservable.Connect();
            });

全体的な処理の都合上Take(4)を使用して最初の4つしか値を通していないのですが、これはおいといて、今まで書いていた処理をSubscribe内にまとめて、最後にdisplayConnectableObservable.Connect();で次の処理のストリームを稼働しています。今回は、処理①が終わったら処理②を行うといった流れにしたかったのでこの次にdisplayConnectableObservableのSubscribeが書かれています。こうすることで処理を直列化できます

感想

  • 結局手続きてきな処理になってしまっているので、もっと宣言的に書き直したほうがよい?