看过几篇讲解UGUI的教程,基本每一篇后面的实例中都会教如何用slider组件实现血条,甚至笔者买了一本有关unity的书,在介绍UGUI的时候也要提一下slider实现血条的事。
但是,slider实现的血条真的好用吗?
slider实现的血条对于初学者很友好,一看就懂,用起来也很方便,但是它本质上通过控制缩放实现的方式在很多情况又不是很好用,比如:你要实现的血条不是纯色的,而是美术交给你的精美绝伦的图片时。
本文将展示一种使用RectMask2D组件实现的血条设计。
演示效果:
组件截图:
Hp添加Bar脚本;Hp两个儿子添加RectMask2D组件;Hp两个孙子添加Image组件(hp图片资源)和HorizontalLayoutGroup组件(为了添加每百血分割线准备的)配置如下:
最后把对应的组件添加到脚本上即可。
代码如下:
using UnityEngine;
using UnityEngine.UI;
namespace ETModel
{
[DisallowMultipleComponent]
[RequireComponent(typeof(RectTransform))]
public class Bar : MonoBehaviour
{
[Range(0.0f, 1.0f)]
[Tooltip("血条剩余血量占比")]
public float Alpha = 1.0f;
[Tooltip("血条遮罩层组件")]
public RectTransform FillRectTrans;
[Tooltip("血条组件")]
public RectTransform HpFillRectTrans;
[Tooltip("渐变血条遮罩层组件")]
public RectTransform TweenRectTrans;
[Tooltip("渐变血条组件")]
public RectTransform HpTweenRectTrans;
[Tooltip("满血血量数值")]
public int BloodVolume;
[Tooltip("当前血量数值")]
[HideInInspector]
public float CurrentBlood;
[Tooltip("每一百血量分割线")]
public Sprite CutLine;
private float tempBlood;
private float newBlood;
private float tweenSpeed;
private bool isHurt;
private float time;
private float width;
public void Awake()
{
InitData();
DrawLine();
}
public void Update()
{
FillRectTrans.GetComponent<RectMask2D>().padding = new Vector4(0, 0, (1 - Alpha) * width, 0);
TweenRectTrans.GetComponent<RectMask2D>().padding = new Vector4(0, 0, width - CurrentBlood * width / BloodVolume, 0);
if (CurrentBlood != Alpha * BloodVolume)
{
if (!isHurt)
{
isHurt = true;
tempBlood = newBlood;
newBlood = Alpha * BloodVolume;
}
else
{
time = 0;
tempBlood = CurrentBlood;
newBlood = Alpha * BloodVolume;
}
}
if(isHurt)
{
time = time >= 1 ? 1 : time+ tweenSpeed * Time.deltaTime;
CurrentBlood = Mathf.Lerp(tempBlood, newBlood, time);
if (time == 1)
{
isHurt = false;
time = 0;
}
}
}
private void InitData()
{
Alpha = 1.0f;
tweenSpeed = 2.0f;
newBlood = BloodVolume;
CurrentBlood = BloodVolume;
time = 0;
isHurt = false;
width = HpFillRectTrans.sizeDelta.x;
}
private void DrawLine()
{
if (BloodVolume != 0)
{
int lineCount = BloodVolume / 100;
float singleHundred = HpFillRectTrans.sizeDelta.x * 100 / BloodVolume;
HpFillRectTrans.GetComponent<HorizontalLayoutGroup>().padding.left = (int)singleHundred;
HpTweenRectTrans.GetComponent<HorizontalLayoutGroup>().padding.left = (int)singleHundred;
HpFillRectTrans.GetComponent<HorizontalLayoutGroup>().spacing = singleHundred;
HpTweenRectTrans.GetComponent<HorizontalLayoutGroup>().spacing = singleHundred;
CreatLine(lineCount, HpFillRectTrans.transform);
CreatLine(lineCount, HpTweenRectTrans.transform);
}
}
private void CreatLine(int number , Transform parent)
{
for (int i = 0; i < number; i++)
{
GameObject go = new GameObject();
Image image = go.AddComponent<Image>();
image.sprite = CutLine;
go.transform.SetParent(parent, false);
}
}
void OnGUI()
{
if (GUI.Button(new Rect(800, 50, 80, 20), "掉血"))
Alpha -= 0.1f;
if (GUI.Button(new Rect(800, 30, 80, 20), "回复"))
{
Alpha = 1.0f;
InitData();
}
}
}
}