Unity3D 多层血条特效

Posted 穿迷彩服的鲨鱼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 血条的渐变效果

Unity3D 血条的渐变效果

Unity中实现多层血条

Unity中实现多层血条

unity3d中怎样制作血条跟随角色运动

Unity3D血条(HP)