LoginSignup
1
0

More than 5 years have passed since last update.

UniRxでUnityのSliderのゲージ処理をつくる

Last updated at Posted at 2019-02-01

とりあえず上昇するやつ

UnityのSliderの作り方は、ググレば出てくるので、説明しないよ


using UnityEngine;
using UniRx;
using UnityEngine.UI;
using System;

public class GargeUniRx : MonoBehaviour
{
    [SerializeField]
    Slider Slider;

    // 現在値
    [SerializeField]
    int StartPoint = 0;

    // 追加分
    [SerializeField]
    int AddPoint = 100;

    // MAX値
    [SerializeField]
    int MaxPoint = 200;

    // ゲージの進む速度
    [SerializeField]
    double MoveTime = 0.2d;

    // ゲージの伸び幅
    [SerializeField, Range(0.01f, 1f)]
    float GargeAddValue = 0.05f;

    bool GargeEnd = false;

    void Start()
    {
        float currentValue = (float)StartPoint / MaxPoint;
        Slider.value = currentValue;
        float endValue = (float) (StartPoint + AddPoint) / MaxPoint;

        GargeObservable(MoveTime).Subscribe(_ => {
            // 伸びーる
            Slider.value += GargeAddValue;
            if(Slider.value >= endValue) {
                Slider.value = endValue;
                GargeEnd = true;
            }
        });
    }

    // UnirRxってIntervalしかつかってなくね?
    IObservable<long> GargeObservable(double _time)
    {
        return Observable.Interval(TimeSpan.FromSeconds(_time)).TakeWhile(_ => !GargeEnd);
    }
}

StartPoint AddPoint MaxPoint
inspectorでいじる目的
※リスタート処理作っていないので、確認するのに、いちいちUnity停止 > Unity再生する必要があるけど

ゲージの Start値End値 より小さくて、End値 が大きいなら、これだけでいい
ただ、(ゲームとかで)よくあるのが、
ゲージが上がりきって、再度0から残りの分のゲージを上げる(レベルアップして最初からにする)処理について

(StartPoint + AddPoint) / MaxPoint が 1より大きいのなら、ゲージが1周するわけで
周回(ループ)する回数を算出すればいい

何言ってんだこいつ?

ゲージが伸び切った(SliderのValueが1fに到達した)ら、
SliderのValueを 0f にする


    void Start()
    {
        float currentValue = (float)StartPoint / MaxPoint;
        Slider.value = currentValue;
        float endValue = (float) (StartPoint + AddPoint) / MaxPoint;
        GargeObservable(MoveTime).Subscribe(_ => {
            // 伸びーる
            Slider.value += GargeAddValue;

            if(Slider.value >= 1f) {
                Slider.value = 0f;
                endValue -= 1f;
            }

            if(Slider.value >= endValue) {
                Slider.value = endValue;
                GargeEnd = true;
            }
        });
    }

ゴリゴリのif文で、美しくないが、
リスタートのときに、一緒に endValue-1f してあげればいい

とりあえず減少するやつ

上昇するときと、やることはたいして変わらない
処理を逆にすればいい


    void Start()
    {
        float currentValue = (float)StartPoint / MaxPoint;
        Slider.value = currentValue;
        float endValue = (float) (StartPoint + AddPoint) / MaxPoint;
        GargeObservable(MoveTime).Subscribe(_ => {
            // 縮ーむ
            Slider.value -= GargeAddValue;

            if(Slider.value <= 0f) {
                Slider.value = 1f;
                endValue = 1f - (endValue + 1f);
            }

            if(Slider.value <= endValue) {
                Slider.value = endValue;
                GargeEnd = true;
            }
        });
    }

上昇の時と違って、
リスタートの時の endValue は、ゲージMAX(1f)から始まるので、計算がちょっと違う
そんな初歩的なことに、ハマったうんこがここにいるらしい

UniRx全然使っていないし、こんな糞コード晒して恥ずかしくないんですか?

そうだね :poop:
じゃあSliderのValueを監視するのをUniRxにしてみようか


    // ゲージの値を監視(1fか0fになったら実行される)
    IObservable<long> GargePoliceObservable()
    {
        return Observable.EveryUpdate().Where(_ => {
            if(AddPoint > 0)
                return Slider.value >= 1f;
            else
                return Slider.value <= 0f;
        }).TakeWhile(_ => !GargeEnd);
    }

Start はこんな感じになる(ゲージ上昇)


    void Start()
    {
        float currentValue = (float)StartPoint / MaxPoint;
        Slider.value = currentValue;
        float endValue = (float) (StartPoint + AddPoint) / MaxPoint;
        GargeObservable(MoveTime).Subscribe(_ => {
            // 伸びーる
            Slider.value += GargeAddValue;

            if(Slider.value >= endValue) {
                Slider.value = endValue;
                GargeEnd = true;
            }
        });

        GargePoliceObservable().Subscribe(_ => {
            Slider.value = AddPoint > 0 ? 0f : 1f;
            endValue = AddPoint > 0 ? endValue - 1f : 1f - (endValue + 1f);
        });
    }

1つの処理に、ガッツリ書くのと大差ない気がする
気分の問題かな?

でもMAX値って変動するよね?

たしかに :poop:
RPGとかの経験値テーブルとかは、

  • レベル1からレベル2になるのに 200
  • レベル2からレベル3になるのに 250

みたいに固定値じゃない

なら頑張って計算してみよう

    static readonly Dictionary<int, int> ExpTableList = new Dictionary<int, int>() {
        // レベル , 次のレベルに上がるのに必要なポイント
        {1, 100 },
        {2, 150 },
        {3, 200 },
        {4, 300 },
        {5, 400 },
    };

    [SerializeField, Range(1, 5)]
    int CurrentLevel = 1;

    float GetCurrentValue()
    {
        if(!ExpTableList.ContainsKey(CurrentLevel)) {
            return 1f;
        }

        return (float)StartPoint / ExpTableList[CurrentLevel];

    }

    float GetEndValue()
    {
        int count = AddPoint > 0 ? 1 : -1;
        int tmpStartPoint = StartPoint;
        int tmpAddPoint = AddPoint;
        float retval = 0f;
        // ゲージ上昇のときだけ
        for(int level = CurrentLevel; level < ExpTableList.Count; level += count) {
            if(!ExpTableList.ContainsKey(level)) {
                break;
            }

            int maxPoint = ExpTableList[level];

            // 必要ポイントより現在値と加算値が大きいなら1fになるね
            if(maxPoint <= tmpStartPoint + tmpAddPoint) {
                retval += (1f - tmpStartPoint / maxPoint);
            } else {
                retval += (float)(tmpStartPoint + tmpAddPoint) / maxPoint;
            }

            tmpAddPoint -= (maxPoint - tmpStartPoint);
            if(tmpAddPoint <= 0) {
                break;
            }

            // 1周したのなら、開始値は0にする
            tmpStartPoint = 0;
        }
        return retval;
    }

レベル毎に1回ごとに Value値を加算しているだけ
ゲージが上昇する場合なら、+1レベルしていく
ゲージが減少する場合なら、-1レベルしていく

しかしコード汚いなぁ
もっと綺麗に書けないものか

1
0
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
1
0