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

## とりあえず上昇するやつ

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

```csharp

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` にする

```csharp

	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` してあげればいい

## とりあえず減少するやつ

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

```csharp

	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全然使っていないし、こんな糞コード晒して恥ずかしくないんですか？

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

```csharp

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

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

```csharp

	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値って変動するよね？

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

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

みたいに固定値じゃない

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

```csharp
	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レベルしていく 

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