端が直線にならないHPゲージの作り方
ゲージをImageのFilledを用いて作成すると、端が直線になってしまいます。そこで、ゲージの形を維持したまま、動かす方法がないかと考え、以下の方法を思いつきました。
※端が直線にならないHPゲージの作り方(Shader)はこちら
Maskを使用した方法
その1
Create→UI→ImageからCanvesに背景用Image、Mask用Imageとゲージ用Imageを作成します。
ゲージ用ImageはMask用Imageの子にします。それぞれにSpriteをアタッチします。Mask用のImageにはゲージのSpriteをアタッチします。
Mask用のImageにAddComponentからMaskを選択します。
あとはゲージ用ImageのPositionを変更すればゲージを動かすことができます。
画像を見てわかるように左端がきれいに処理されていないことがわかります。これは、Maskがステンシルバッファで処理されているためです。そこで、Maskを使用した両端がきれいに表示されるゲージを作りました。
その2
Maskを使用してきれいに処理できないものかと考えた結果、新たにゲージが半分だけ表示されるMask画像を作成し、半分表示したゲージを左右に配置する方法で作成しました。
その1と同じようにImageを作成します。Mask用Imageには上のMask画像を使用します。そして、作成したImageを複製し、RotationのYに180と入力し回転させます。
作成したゲージを動かすには、左右のMask用ImageをX方向へ動かし、その子であるゲージ用画像を反対方向へ動かすことでゲージを動かすことができます。例えばMask用ImageのPos Xを-50としたとき、ゲージ用ImageのPosは50とすると左端を動かさずにゲージを縮めることができます。
・Script
目的の動作するかを確認するためにScriptを作成しました。ゲージの背景、ゲージ及びマスク用SpriteとSliderをアタッチすれば動作します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class HPGaugeMask : MonoBehaviour { public GameObject preSlider; public Sprite preBack, preGauge, preMask; private GameObject objHPGauge, objSlider; private GameObject[] objMask = new GameObject[2]; private GameObject[] objGauge = new GameObject[2]; private Slider slider; // Use this for initialization void Start () { Image img; RectTransform rect; Transform trfCanvas = GameObject.Find("Canvas").transform; objHPGauge = new GameObject(); objHPGauge.transform.SetParent(trfCanvas); objHPGauge.transform.localPosition = Vector3.zero; objHPGauge.AddComponent<CanvasRenderer>(); img = objHPGauge.AddComponent<Image>(); img.sprite = preBack; rect = objHPGauge.GetComponent<RectTransform>(); rect.sizeDelta = new Vector2(256, 32); objSlider = Instantiate(preSlider, trfCanvas); objSlider.transform.localPosition = new Vector3(0, -50f, 0); slider = objSlider.GetComponent<Slider>(); for (int i = 0; i < 2; i++) { objMask[i] = new GameObject(); objMask[i].transform.SetParent(objHPGauge.transform); objMask[i].transform.localPosition = Vector3.zero; objMask[i].AddComponent<CanvasRenderer>(); img = objMask[i].AddComponent<Image>(); img.sprite = preMask; rect = objMask[i].GetComponent<RectTransform>(); rect.sizeDelta = new Vector2(img.sprite.rect.width, img.sprite.rect.height); Mask mask = objMask[i].AddComponent<Mask>(); mask.showMaskGraphic = false; objGauge[i] = new GameObject(); objGauge[i].transform.SetParent(objMask[i].transform); objGauge[i].transform.localPosition = Vector3.zero; objGauge[i].AddComponent<CanvasRenderer>(); img = objGauge[i].AddComponent<Image>(); img.sprite = preGauge; rect = objGauge[i].GetComponent<RectTransform>(); rect.sizeDelta = new Vector2(img.sprite.rect.width, img.sprite.rect.height); } objMask[1].transform.localEulerAngles = new Vector3(0, 0, 180); } // Update is called once per frame void Update () { if (Input.GetMouseButton(0)) { for(int i = 0; i < 2; i++) { float pos = 123f * slider.value; objMask[i].transform.localPosition = new Vector3(-pos, 0, 0); objGauge[i].transform.localPosition = new Vector3(pos, 0, 0); } } } } |
・実行結果
上記Scriptを実行した結果はこちらです。両端の形状を変形させずにゲージを動かすことができました。
ImageのFilledを使用した方法
その2で作成したゲージと同じものが、Mask画像を使用せずにImageのFilledを使えば作成できるのでは、と考えScriptを作成しました。
・Script
作成したScriptはこちらです。ゲージ及びマスク用SpriteとSliderをアタッチすれば動作します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class HPGaugeFill : MonoBehaviour { public GameObject preSlider; public Sprite preBack, preGauge; private GameObject objHPGauge, objSlider; private GameObject[] objGauge = new GameObject[2]; private Image[] imgGauge = new Image[2]; private Slider slider; private float gaugeWidth; // Use this for initialization void Start () { Image img; RectTransform rect; Transform trfCanvas = GameObject.Find("Canvas").transform; objHPGauge = new GameObject(); objHPGauge.transform.SetParent(trfCanvas); objHPGauge.transform.localPosition = Vector3.zero; objHPGauge.AddComponent<CanvasRenderer>(); img = objHPGauge.AddComponent<Image>(); img.sprite = preBack; rect = objHPGauge.GetComponent<RectTransform>(); rect.sizeDelta = new Vector2(img.sprite.rect.width, img.sprite.rect.height); objSlider = Instantiate(preSlider, trfCanvas); objSlider.transform.localPosition = new Vector3(0, -50f, 0); slider = objSlider.GetComponent<Slider>(); for (int i = 0; i < 2; i++) { objGauge[i] = new GameObject(); objGauge[i].transform.SetParent(objHPGauge.transform); objGauge[i].transform.localPosition = Vector3.zero; objGauge[i].AddComponent<CanvasRenderer>(); imgGauge[i] = objGauge[i].AddComponent<Image>(); imgGauge[i].sprite = preGauge; imgGauge[i].type = Image.Type.Filled; imgGauge[i].fillMethod = Image.FillMethod.Horizontal; imgGauge[i].fillAmount = 0.5f; rect = objGauge[i].GetComponent<RectTransform>(); rect.sizeDelta = new Vector2(imgGauge[i].sprite.rect.width, imgGauge[i].sprite.rect.height); } imgGauge[0].fillOrigin = (int)Image.OriginHorizontal.Left; imgGauge[1].fillOrigin = (int)Image.OriginHorizontal.Right; gaugeWidth = imgGauge[0].sprite.rect.width; } // Update is called once per frame void Update () { if (Input.GetMouseButton(0)) { for (int i = 0; i < 2; i++) { imgGauge[i].fillAmount = (1 - slider.value) * 0.5f; } float pos = gaugeWidth * slider.value; objGauge[1].transform.localPosition = new Vector3(-pos, 0, 0); } } } |
・実行結果
Maskを使用した場合と同じ動作をしています。
終わりに
Unityに用意されている機能を用いて作成したところ、目的の動作を行ってくれました。しかし、もっと良い方法がないものかと考えた結果、shaderで同様の動作を実現できるのではと考え、新たにshaderを作成しました。このことに関しては次回、記事にする予定です。
※記事を作成しました。
端が直線にならないHPゲージの作り方(Shader)はこちら
-
前の記事
軌道予測線をUIに描画 2018.09.12
-
次の記事
端が直線にならないHPゲージの作り方(Shader) 2018.09.18
コメントを書く