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 多层血条特效的主要内容,如果未能解决你的问题,请参考以下文章