Unity3D 多层血条特效
Posted 穿迷彩服的鲨鱼
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity3D 多层血条特效相关的知识,希望对你有一定的参考价值。
提示:素材来源网络,侵权必删
Unity3D 多层血条特效
效果图
鼠标左右键控制其血条增减
提示:以下是本篇文章正文内容,下面案例可供参考
一、准备项目工程
1.创建项目,准备一个物体如图
提示:Hierarchy面板需准备如下
2.制作血条预制体,把此预制体放在Resources下
提示:创建四个Image按此排列
二、效果代码
1.创建Controller脚本挂在Hierarchy下创建的物体上
代码如下(示例):
using System.Collections.Generic;
using UnityEngine;
namespace HKZ
/// <summary>
/// 测试代码
/// </summary>
public class Controller : MonoBehaviour
private LifeBar bar;
private void Start()
Canvas canvas = FindObjectOfType<Canvas>();
if (canvas == null)
Debug.LogError("场景中没有Canvas组件");
return;
SpawnLifeBar(canvas);
/// <summary>
/// 生成血条
/// </summary>
/// <param name="canvas"></param>
private void SpawnLifeBar(Canvas canvas)
GameObject prefab = Resources.Load<GameObject>("LifeBar");
bar = Instantiate(prefab, canvas.transform).AddComponent<LifeBar>();
List<LifeBarDate> date = new List<LifeBarDate>();
date.Add(new LifeBarDate(null, Color.green));
date.Add(new LifeBarDate(null, Color.red));
date.Add(new LifeBarDate(null, Color.yellow));
bar.Init(transform, 350, date);
/// <summary>
/// 控制物体移动
/// </summary>
private void Update()
if (Input.GetKey(KeyCode.A))
Move(Vector3.left);
if (Input.GetKey(KeyCode.D))
Move(Vector3.right);
if (Input.GetKey(KeyCode.W))
Move(Vector3.up);
if (Input.GetKey(KeyCode.S))
Move(Vector3.down);
if (Input.GetMouseButtonDown(0))
int ran = Random.Range(10, 50);
bar.ChangeLife(-ran);
if (Input.GetMouseButtonDown(1))
int ran = Random.Range(10, 50);
bar.ChangeLife(ran);
/// <summary>
/// 物体移动
/// </summary>
/// <param name="dircetion"></param>
private void Move(Vector3 dircetion)
transform.Translate(dircetion * Time.deltaTime * 5);
2.创建LifeBar脚本
代码如下(示例):
using System.Collections.Generic;
using UnityEngine;
namespace HKZ
public class LifeBar : MonoBehaviour
private Transform _target;//要跟随的物体
private Vector3 offset;//跟随物体的偏移量
private List<LifeBarDate> Dates;
private LifeBarItem nextBar;//下一个血条
private LifeBarItem currentBar;//当前血条
private float unitLifeScale;//血条大小
private int currentIndex;//当前是哪个血条
/// <summary>
/// 初始化数据
/// </summary>
/// <param name="target"></param>
/// <param name="lifeMax"></param>
/// <param name="lifeBarDates"></param>
public void Init(Transform target, int lifeMax, List<LifeBarDate> lifeBarDates)
currentIndex = 0;
_target = target;
offset = GetOffset(target);
Dates = lifeBarDates;
nextBar = transform.Find("NextBar").gameObject.AddComponent<LifeBarItem>();
currentBar = transform.Find("CurrentBar").gameObject.AddComponent<LifeBarItem>();
nextBar.Init();
currentBar.Init();
RectTransform rect = GetComponent<RectTransform>();
unitLifeScale = rect.rect.width * Dates.Count / lifeMax;//拿到血条大小
SetBarDate(currentIndex, lifeBarDates);
/// <summary>
/// 得到目标物最上方位置
/// </summary>
/// <param name="target"></param>
/// <returns></returns>
private Vector3 GetOffset(Transform target)
Renderer renderer = target.GetComponent<Renderer>();
if (renderer == null)
return Vector3.zero;
return Vector3.up * renderer.bounds.max.y;
private void Update()
if (_target == null)
return;
//跟随目标物
transform.position = Camera.main.WorldToScreenPoint(_target.position + offset + new Vector3(0, 9, 0));
/// <summary>
/// 更新血条变化
/// </summary>
/// <param name="value"></param>
public void ChangeLife(float value)
float Width = currentBar.ChangeLife(value * unitLifeScale);
if (Width < 0 && ChangeIndex(1))
Exchange();
currentBar.transform.SetAsLastSibling();
nextBar.ResetToWidth();
SetBarDate(currentIndex, Dates);
ChangeLife(Width / unitLifeScale);
else if (Width > 0 && ChangeIndex(-1))
Exchange();
currentBar.transform.SetAsLastSibling();
currentBar.ResetToZero();
SetBarDate(currentIndex, Dates);
ChangeLife(Width / unitLifeScale);
/// <summary>
/// -1代表加血 1代表减血
/// </summary>
/// <param name="symbol"></param>
private bool ChangeIndex(int symbol)
int index = currentIndex + symbol;
if (index >= 0 && index < Dates.Count)
currentIndex = index;
return true;
return false;
private void Exchange()
var temp = nextBar;
nextBar = currentBar;
currentBar = temp;
public void SetBarDate(int index, List<LifeBarDate> date)
if (index < 0 || index >= date.Count)
return;
currentBar.SetDate(Dates[index]);
if (index + 1 >= date.Count)
nextBar.SetDate(new LifeBarDate(null, Color.white));
else
nextBar.SetDate(date[index + 1]);
/// <summary>
/// 血条数据
/// </summary>
public struct LifeBarDate
public Sprite BarSprite;
public Color BarMainColor;
public LifeBarDate(Sprite barSprite, Color barMainColor)
BarSprite = barSprite;
BarMainColor = barMainColor;
3.创建LifeBarItem脚本
代码如下(示例):
using DG.Tweening;
using UnityEngine;
using UnityEngine.UI;
namespace HKZ
public class LifeBarItem : MonoBehaviour
private RectTransform rect;
public RectTransform Rect
get
if (rect == null)
rect = GetComponent<RectTransform>();
return rect;
private Image image;
public Image Image
get
if (image == null)
image = GetComponent<Image>();
return image;
private float defaultWidth;
private LifeBarItem child;
/// <summary>
/// 初始化数据
/// </summary>
public void Init()
if (transform.Find("AdditionBar") != null)
child = transform.Find("AdditionBar").gameObject.AddComponent<LifeBarItem>();
defaultWidth = Rect.rect.width;
/// <summary>
/// 设置数据
/// </summary>
/// <param name="date"></param>
public void SetDate(LifeBarDate date)
Image.color = date.BarMainColor;
if (date.BarSprite != null)
Image.sprite = date.BarSprite;
if (child != null)
child.SetDate(date);
/// <summary>
/// 更变血条
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public float ChangeLife(float value)
if (child != null)
child.DOKill();
child.Image.color = Image.color;
child.Rect.sizeDelta = Rect.sizeDelta;
child.Image.DOFade(0, 0.5f).OnComplete(() => child.ChangeLife(value));
Rect.sizeDelta += Vector2.right * value;
return GetOutRange();
/// <summary>
/// 得到当前血条
/// </summary>
/// <returns></returns>
private float GetOutRange()
float offset = 0;
if (Rect.rect.width < 0)
offset = Rect.rect.width;
ResetToZero();
else if (Rect.rect.width > defaultWidth)
offset = Rect.rect.width - defaultWidth;
ResetToWidth();
return offset;
/// <summary>
/// 扣血显示下一条时恢复默认状态
/// </summary>
public void ResetToZero()
Rect.sizeDelta = Vector2.zero;
/// <summary>
/// 加血显示下一条时恢复默认状态
/// </summary>
public void ResetToWidth()
Rect.sizeDelta = Vector2.right * defaultWidth;
效果出来了吧!
总结
以上是关于Unity3D 多层血条特效的主要内容,如果未能解决你的问题,请参考以下文章
解决Unity3D中多层级结构子物体旋转受父物体尺寸影响的问题