本実装のサンプルはこちらに用意しています。Unity Hubからプロジェクトとして立ち上げてみてください。
https://github.com/konbraphat51/GaugePrototype
ブラウザ上で動くデモ:https://konbraphat51.github.io/GaugePrototypeWEBGL/
作りたいもの
ブラウザ上で動くデモ:https://konbraphat51.github.io/GaugePrototypeWEBGL/
上図のように、任意の形の図形が、片側から段々着色されていくようなゲージをspriteで作ります。
もしImageでの実装でよければ、こちらの記事の実装がとてもやりやすいです。
しかしImageでの実装となると、表示優先度(どちらが前でどちらが奥か)の管理がやりづらかったりして、Spriteでやれたらなと思い立ち、今回の記事に至りました。
ちなみに、応用として「成功ゾーン」も試みています。(上図、黄色の部分)
気分としてはドラクエ11の「不思議な鍛冶」のゲージですね。このゾーンに到達できなかったり超過してしまうと失敗してしまうやつ。
用意する画像(通常ゲージ)
このために、下記の画像を用意しました。(png透過処理済みです)
作戦(通常ゲージ)
まずは土台の上に着色のスプライトをそのまま上乗せしちゃいます。
そこで、先ほど用意した半分透過長方形をマスクとして使うと、なんとゲージっぽくなるではないですか。
すなわち、我々がすべきことは、表示する割合に応じて、このマスクを移動していけばいいというわけです。
なぜわざわざ半分透過した画像を用意したかというと、下図のようにピボットがちょうど表示する部分と隠される部分の境界に位置するので、このマスク全体の座標がそのまま境界線の座標になり、指定がやりやすくなるからです。
実装(通常ゲージ)
まずはスクリプト。これはどれにアタッチしても大丈夫です。私は土台スプライトにアタッチしました。
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;
}
}
一番親のGaugeが土台スプライト、
Right, Leftは空スプライト、
GaugeReachedが着色スプライト、
MovingMaskが先述の動かすマスクです。
Gauge:土台スプライト
RectTransform
とGauge
をアタッチ。
RectTransformをつけることによって、後述のRight, Leftの座標指定が楽になります。
Gaugeにはそれぞれ対応するオブジェクトをアタッチ。最後のGoing Right
は右向きに溜めていくならチェックをつけ、左向きなら外してください
Right, Left:空スプライト
これにもRectTransform
をアタッチ。すると楽々にRightを右端に、Leftを左端に配置できます。
GaugeReached
着色スプライトはそのまま子オブジェクトとして上乗せ。元画像のサイズがあっていればPositionを(0,0,-1)にすることでキレイに重なります。(Z座標は上に乗せるため負数に)
これにSorting Group
をアタッチしてください。後述のMovingMaskの適用範囲がこのスプライトのみにするためです。
MovingMask
これは右向きに溜めていくなら左半分の長方形画像を、左向きに溜めていくなら右半分の長方形画像でSpriteMask
を作ってください。
これで通常ゲージは完成です!
成功ゾーンは続編の記事にて!