UniRxの勉強 No.2

2020年4月20日月曜日

UniRx Unity

t f B! P L

前回はUnityの教科書chapter2を真似てUniRxをDebug.Log()でいじって遊んでみた。

今回はUnityの教科書chapter3のルーレットをUniRxベースで作ってみる。
(なぜunityの教科書のプロジェクト作ってるかは前回のを見て。)

ルーレットと針の画像をインポートしてシーンに配置


では、スクリプトを書いていこう。

ルーレットを作る。

設計

ルーレットの動作だけど、Unityの教科書では
1、GameStartと同時にある一定速度でルーレットが回転
2、クリックしたら減速する

という動作である。

そのまま作っても良いけど、ちょっとアレンジして
1、GameStartでルーレットが停止状態から加速。
2、ある速度になったら回転速度固定。
3、速度が一定になったらクリック入力を受け付ける
4、クリックで減速
にする。

完成品

設計通りUniRxでプログラムを書くとこんな感じになった。

このツイートでも言っているが、きれいに処理を隠蔽することができた。
また、それだけでなく、隠蔽した処理の部分もかなりわかりやすく書くことができた。

スクリプト全体

このスクリプトははじめてのUniRxの64ページを参考にした。
using System.Collections;
using UnityEngine;
using UniRx;
using System;

public class RouletteController :MonoBehaviour
{
    [SerializeField] private float maxSpeed = 1000, acceleration = 1.1f, deceleration = 0.99f;

    void Start() {
        Observable.FromCoroutine<float>(observer => RouletteSystem(observer, maxSpeed, acceleration, deceleration))
                  .Subscribe(speed => transform.Rotate(0, 0, speed * Time.deltaTime));
    }

    IEnumerator RouletteSystem(IObserver<float> observer, float _maxSpeed, float _acceleration, float _deceleration) {
        float currentSpeed = 1;

        //ルーレットの加速
        while (currentSpeed < _maxSpeed) {
            currentSpeed *= _acceleration;

            observer.OnNext(currentSpeed);

            yield return null;
            Debug.Log(currentSpeed);
        }
        currentSpeed = _maxSpeed;
        observer.OnNext(currentSpeed);

        //ストップの入力待ち
        bool Continue = true;
        while (Continue) {
            if (Input.GetMouseButtonDown(0)) {
                Continue = false;
                observer.OnNext(_maxSpeed);
            }

            observer.OnNext(_maxSpeed);

            Debug.Log(currentSpeed);

            yield return null;
        }

        //減速処理
        while (currentSpeed > 1) {
            currentSpeed *= _deceleration;

            observer.OnNext(currentSpeed);

            yield return null;
            Debug.Log(currentSpeed);

        }
        observer.OnNext(0);


        observer.OnCompleted();
    }
}

スクリプト解説

Start()

Observable.FromCoroutine<float>(/*省略*/)
これは引数のコルーチンをObservable(ストリーム)に変換するメソッドで、返り値はfloat
詳しくは

Observable.FromCoroutine<T>()
返り値  : IObservable<T>
第一引数 : Func coroutine コルーチン本体
第二引数 : bool nullAsNextUpdate = true nullの時にOnNextを発行しない,default = true

.Subscribe(speed => transform.Rotate(0, 0, speed * Time.deltaTime));
で関数を登録。
登録した関数は
引数 speed(float型)
内容 transform.transform.Rotate(0, 0, speed * Time.deltaTime));


Start()で、Observable(ストリーム)を定義した。
これは、ただ定義しただけなので、OnNext()などで呼ばれないと実行されない。

コルーチン

コルーチン内でOnNext()している。

あと、最後にOnCompleted()を呼んでObservebleを片付けることを忘れないように。

引数は
IObserver<float> observer
ー 先ほどStart()で定義したObservable
float _maxSpeed
ー ルーレットの回転の最大速度
float _acceleration
ー ルーレットの加速割合
float _deceleration
ー ルーレットの減速割合
OnNext()によって、先ほどのObservableに登録した関数が実行される。


登録した関数は引数にfloat型の引数をとる関数なので、OnNext()で、floatの値を送る。

この送るfloatの値状況によって変化させることでルーレットの回転速度を変化させている。

さらにその状況はコルーチンに書いたことで、上から下へ流れるように1つ1つ分けて書くことができ、非常にわかりやすくなった。

まとめ(感想)

今回はUniRxを使ってコルーチンをObservable(ストリーム)に変換した。

これによって、Update()や、状況(State)を保持するメンバをなくし、処理の流れがわかりやすくなった。

また、Observableの複雑な処理をコルーチンに書いたので、Start()での実装もシンプルになった。

次回は Uniyの教科書chapter4 の寸止めゲーム、「SwipeCar」をUniRxベースで作っていこうと思う。

次回(未作成)
-今回のUnityプロジェクト-

Contribute to 2357or/UniRx_study2 development by creating an account on GitHub.

自己紹介

自分の写真
県立高校理数科2年
Unity2年目
Twitter
Note

人気の投稿

[Vim] coc.nvim + coc-clangdの構文チェックでboostのエラーが発生する

C++の拡張ライブラリ、Boost。 AtCoderでも使用が認められているライブラリです。 様々な便利機能が搭載されています。 競技プログラミングで使えるBoostライブラリ 初級編 から一部抜粋すると、 boost...

QooQ