【Unity】Spritesでゲージを作る、成功ゾーンを添えて①【サンプル有】

:::note
本実装のサンプルはこちらに用意しています。Unity Hubからプロジェクトとして立ち上げてみてください。
https://github.com/konbraphat51/GaugePrototype
ブラウザ上で動くデモ：https://konbraphat51.github.io/GaugePrototypeWEBGL/

次の記事：https://qiita.com/konbu9640/items/aa4696beb85a64854bbd
:::

# 作りたいもの
ブラウザ上で動くデモ：https://konbraphat51.github.io/GaugePrototypeWEBGL/
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602537/24f035af-0643-ed19-605b-3bc275caa97b.png)
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602537/d614ce78-a638-c86a-7a0f-7f3c551859dc.png)
上図のように、任意の形の図形が、片側から段々着色されていくようなゲージをspriteで作ります。

もしImageでの実装でよければ、[こちらの記事](https://gomafrontier.com/unity/492)の実装がとてもやりやすいです。
しかしImageでの実装となると、表示優先度（どちらが前でどちらが奥か）の管理がやりづらかったりして、Spriteでやれたらなと思い立ち、今回の記事に至りました。

ちなみに、応用として「成功ゾーン」も試みています。（上図、黄色の部分）
気分としてはドラクエ11の「不思議な鍛冶」のゲージですね。このゾーンに到達できなかったり超過してしまうと失敗してしまうやつ。

# 用意する画像（通常ゲージ）
このために、下記の画像を用意しました。（png透過処理済みです）

土台
![Slot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602537/66091597-9feb-8b43-88eb-fd715b8ab6b0.png)

緑の着色
![Fill.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602537/1c80c8ac-d22b-e1e3-0a7b-f80a8573a667.png)

右半分が透過されている長方形（マスク用）
![LeftHalf.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602537/c948de7d-b3c6-b47e-6635-ceabcd230e41.png)

左半分が透過されている長方形（マスク用）
![LeftHalf (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602537/a9adf8f0-b490-6b9a-f190-631e7f961e6c.png)

# 作戦（通常ゲージ）

まずは土台の上に着色のスプライトをそのまま上乗せしちゃいます。
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602537/18b00d6d-3b5e-375f-6aa0-1f0d3deff71e.png)

そこで、先ほど用意した半分透過長方形をマスクとして使うと、なんとゲージっぽくなるではないですか。
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602537/264cfe92-91a4-53d8-4b6c-91649102c95b.png)

すなわち、我々がすべきことは、表示する割合に応じて、このマスクを移動していけばいいというわけです。

なぜわざわざ半分透過した画像を用意したかというと、下図のようにピボットがちょうど表示する部分と隠される部分の境界に位置するので、このマスク全体の座標がそのまま境界線の座標になり、指定がやりやすくなるからです。
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602537/2946dcfd-dca3-bc55-0484-74799268b931.png)



# 実装（通常ゲージ）
まずはスクリプト。これはどれにアタッチしても大丈夫です。私は土台スプライトにアタッチしました。
```C#:Gauge.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Must to call Initialize() first
/// </summary>
public class Gauge : MonoBehaviour
{
    //where Fill comes until
    private float showingRatio = 0f;

    [SerializeField] private GameObject rightEdgeObject;
    private float rightEdge;
    [SerializeField] private GameObject leftEdgeObject;
    private float leftEdge;

    [SerializeField] private GameObject reachedMovingMask;

    [Tooltip("Reverse")]
    [SerializeField] public bool goingRight;

    private void Start()
    {
        //set edge variable
        GetEdge();
    }

    /// <summary>
    /// this must be called
    /// </summary>
    /// <param name="showingRatio"></param>
    public void Initialize(float showingRatio)
    {
        //initialize variable
        this.showingRatio = showingRatio;

        //in case if this come earlier than Start()
        GetEdge();

        //Move to start point
        Animate();
    }

    /// <summary>
    /// Displaying gauge changes by here. 
    /// </summary>
    /// <param name="ratio"></param>
    public void SetRatio(float ratio)
    {
        showingRatio = ratio;

        //guard
        if (showingRatio < 0f) showingRatio = 0f;
        if (showingRatio > 1f) showingRatio = 1f;

        Animate();
    }

    //reached sprite move by here.
    private void Animate()
    {
        //where the mask position go
        float edgePosX = GetHorizontalPosition(showingRatio);

        //move the mask
        reachedMovingMask.transform.position = new Vector2(edgePosX, reachedMovingMask.transform.position.y);
    }

    private void GetEdge()
    {
        rightEdge = rightEdgeObject.transform.position.x;
        leftEdge = leftEdgeObject.transform.position.x;
    }

    protected float GetHorizontalPosition(float ratio)
    {
        float output = 0f;

        switch (goingRight)
        {
            case false:
                //going left
                output = rightEdge - (rightEdge - leftEdge) * ratio;
                break;
            case true:
                //going right

                output = leftEdge + (rightEdge - leftEdge) * ratio;
                break;
        }

        return output;
    }
}

```

ゲージのオブジェクト構成は下図のようにしています。
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602537/1c8a3912-9061-669a-e8cb-9b2910e304e3.png)

一番親のGaugeが土台スプライト、
Right, Leftは空スプライト、
GaugeReachedが着色スプライト、
MovingMaskが先述の動かすマスクです。

### Gauge：土台スプライト
![Untitled1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602537/d3bcf19d-f6be-3b94-594b-f9cffa478586.png)
`RectTransform`と`Gauge`をアタッチ。
RectTransformをつけることによって、後述のRight, Leftの座標指定が楽になります。
Gaugeにはそれぞれ対応するオブジェクトをアタッチ。最後の`Going Right`は右向きに溜めていくならチェックをつけ、左向きなら外してください

### Right, Left：空スプライト
![Untitled2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602537/e2f04d85-dab2-8ca4-5f18-25380a466150.png)
これにも`RectTransform`をアタッチ。すると楽々にRightを右端に、Leftを左端に配置できます。

### GaugeReached
着色スプライトはそのまま子オブジェクトとして上乗せ。元画像のサイズがあっていればPositionを(0,0,-1)にすることでキレイに重なります。(Z座標は上に乗せるため負数に）
これに`Sorting Group`をアタッチしてください。後述のMovingMaskの適用範囲がこのスプライトのみにするためです。

### MovingMask
これは右向きに溜めていくなら左半分の長方形画像を、左向きに溜めていくなら右半分の長方形画像で`SpriteMask`を作ってください。

これで通常ゲージは完成です！

成功ゾーンは[続編の記事](https://qiita.com/konbu9640/items/aa4696beb85a64854bbd)にて！