【Unity】プログレスバーを"いい感じ"に実装する

今回はUnityのプログレスバーをいい感じに実装していこうと思います。
# プログレスバーって何？
>wikipediaより一部引用
>
プログレスバー（英: Progress Bar）とは、長時間かかるタスクの進捗状況がどの程度完了したのかを視覚的・直感的に表示するもので、グラフィカルユーザインタフェースの要素（ウィジェット）の一つである。しばしば、ダウンロードやファイル転送のようにパーセント形式で表示される際に使われる。プログレスメーター （英: Progress Meters）とも呼ばれる。
![progres_bar.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241870/2c69ad6c-1c48-30f5-8848-3d32fa76a2ef.gif)

よくゲームとかで見かけるやつです！

# いい感じとは？

普段、ネットとかで【プログレスバー 実装】について調べてみると、様々な言語で0% ~ 100%までを等間隔で表示させたりするものが多く紹介されています。
↓↓こんな感じで↓↓

```c#
float progress = 0f;
Text progress_text = GetComponent<Text>();
for( int i = 0; i < hoge.length; i++ ) {
  progress = (float)( i / hoge.length ) * 100f;
  progress_text.text = progress.ToString("f2") + "%";
}
```
私も普段はこのように実装していたのですが、ふとゲームで遊んでいると等間隔じゃなくて、何か序盤は早くて徐々にゆっくりな動きをしているように見えました。

そこで、色々なサイトで同じように考えている人がいないか探してみたところ、TEDで紹介で同じようなことが紹介されていました。

[Transcript of "私たちを安心させてくれるプログレスバー"](https://www.ted.com/talks/daniel_engber_how_the_progress_bar_keeps_you_sane/transcript?language=ja#t-215370)

つまり、最初を早くすることで心理学的に、ユーザーからは実際よりも早く進んでいるという感じるそうです。

なので、今回は $y=x と y=\sqrt{x}$ と $y=\sqrt[3]{x}$の３つを実装していこうと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241870/64deb695-b3e0-ce17-5814-b61834a3c7da.png)

長いので先に実行結果だけを見たい人は一番下に動画を載せてます！！

# 実装

## 画像を準備する

まず、Unityでプログレスバーを実装するには円の画像を用意します。
今回は適当にPowerPointで適当に円を作りました(白いので見えにくいですがあります)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241870/baee54f5-bac7-3aee-5287-25a9972c8de7.png)

↑右クリックしてDLしてください。

## Unityで2Dのプロジェクトを新規作成する
私は今回、「ProgressBarText」という名前のプロジェクトを作成しました。(TextとTestのスペル間違えました…)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241870/31aab6f0-034c-f5ea-626b-bd54c0bc279b.png)

## 背景色を変える

そのままでもいいのですが、文字をみやすくするために「Main Camera」→「Camera」→「Background」を押してカラーパレットから「Silver」を選択しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241870/6642bf92-cdf9-6a6b-cc78-57c899ddc495.png)

## DLした画像をImagesをフォルダに入れる

そして、Assetsのなかに「Images」フォルダを作成して、その中に先ほどDLした円の画像をドラッグ&ドロップします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241870/460cb445-bf84-5757-85c9-387fdee9f733.png)

## プログレスバーの作成

まずは、Hierarchyの中に「Canvas」を作成して「Render Mode」を「Screen Space – Camera」に変更。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241870/d7420b6a-b6e0-ae08-d2cc-ce3c5465719b.png)

そして、「Render Camera」を「Main Camera」に設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241870/ab62446f-d435-b141-3a9a-603ae3849342.png)

こちらのサイトをみながら、実際に作ってみる。
[【Unity】uGUIで円形のプログレスバーを簡単に作る](http://ghoul-life.hatenablog.com/entry/2018/01/31/212932)

そして、サイズを「ProgressBar」は300×300に、「Center」は250×250に変更。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241870/b76d8fd4-58f2-08df-25ff-e738b1a6a22e.png)

## 進捗率用のTextとラベル用のTextを作成して1つのGameObjectにまとめる

進捗率を表示するため「ProgressText」とラベルとして表示するための「Label」というTextオブジェクトを作成。
その後、Canvasの中に「X_default」という名前で空のGameObjectを作成し、「ProgressBar」「ProgressText」「Label」を「X_default」の下に移動させる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241870/eeafbe18-bdbe-701a-177a-5efbac8b3a66.png)

## 作成したX_defaultを複製して名前を変える

作成したX_defaultをコピーして、「X_pow_2」「X_pow_3」という名前にリネームする。
そして、均等になるように調節してそれぞれラベルとプログレスバーの色を変える。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241870/b067776b-a89c-b97d-ace3-ddd94a18b4a0.png)

## スクリプトを作成する

Assetsのなかに「Scripts」フォルダを作成して、その中に「ProgressController」と「ButtonController」という名前で2つC#スクリプトを作成する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241870/673c2866-c7d8-77b4-245d-8f4d36383336.png)

## 作成したスクリプトにコピペする

```c#:ProgressController.cs
using System.Collections;
using UnityEngine;
using UnityEngine.UI;

/// <summary>
/// プログレスバーのコントロールを行うクラス
/// </summary>
public class ProgressController : MonoBehaviour {

	[SerializeField] private Text progress_text;	// 進捗率
	[SerializeField] private Image progress_bar;    // 進捗バー
	[SerializeField] private int pow_value;		// 進捗率を何乗するか


	/// <summary>
	/// 1F目に呼ばれる関数
	/// </summary>
	void Start() {
		// UIを初期化する
		progress_text.text = "0.00%";
		progress_bar.fillAmount = 0f;
	}

	/// <summary>
	/// プログレスバーをぐるぐるさせる関数
	/// </summary>
	/// <returns>イテレータを返す</returns>
	public IEnumerator StartProgress() {

		// 重い処理のつもり
		for( int i = 0; i < 2000; i++ ) {

			// 進捗率
			float progress = i / 2000f;
			// 進捗率をpow_value乗する
			float pow_progerss = Mathf.Pow(progress, 1/(float)pow_value);

			// それぞれ代入する
			progress_bar.fillAmount = pow_progerss;
			progress_text.text = (pow_progerss*100f).ToString("f2") + "%";

			yield return null;
		}

		progress_text.text = "100%";
		progress_bar.fillAmount = 1f;
	}
}
```

```c#:ButtonController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ButtonController : MonoBehaviour {

	[SerializeField] ProgressController x_default;
	[SerializeField] ProgressController x_pow_2;
	[SerializeField] ProgressController x_pow_3;


	/// <summary>
	/// ボタンが押されたらプロパティのプログレスバーを動かす
	/// </summary>
	public void OnClickStart() {

		// それぞれのプログレスバーを動かす
		StartCoroutine( x_default.StartProgress() );
		StartCoroutine( x_pow_2.StartProgress() );
		StartCoroutine( x_pow_3.StartProgress() );
	}
}
```

平方根をとるには、Mathf.Pow関数の第二引数を小数にすることで取れる。

## 同時に実行するためスタートボタンを作成する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241870/d1a42f37-249c-69c1-cb5e-873cbf435a09.png)

## スクリプトをアタッチする

スクリプトの作成が終わったので、作成した「Button」に「ButtonController」、「X_default」「X_pow_2」「X_pow_3」にそれぞれ「ProgressController」をアタッチする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241870/c538322e-47b2-a30d-9ebb-c66b712706ed.png)

## それぞれプロパティをセットする

それぞれのGameObjectに対して、プロパティをセット。
【Button】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241870/15e8e3a8-f0a5-056b-a0bb-697a36fdf962.png)

【X_default】【X_pow_2】【X_pow_3】
この3つはほとんどやり方が同じなので、代表として「X_default」のセット方法だけを紹介します。
それぞれの子のProgressBarとProgressTextをセットするのは同じですが、Pow_valueのところだけX_pow2では「2」、X_pow_3では「3」をセットする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241870/64359cb3-b975-4268-74e5-307d96a7c711.png)

## スタートボタンにクリックされた時の関数を実装する

まず、赤の四角で囲われている「＋」ボタンを押すことで関数をセットできる状態になるので、押したら「Button」を画像のようにドラッグ&ドロップする。そして、すぐ右上のボタンを押して画像のように「OnClickStart()」を押すことでセットが完了する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241870/8bce0db4-fdd5-0750-6549-ecfd402ead7e.png)

# 実行！！

[![IMAGE ALT TEXT HERE](http://img.youtube.com/vi/fQNHysZ-xU0/0.jpg)](https://www.youtube.com/watch?v=fQNHysZ-xU0)

このように、プログラムの実行時間自体はどれも同じですが、体感速度が明らかに違うことが分かります！！