【Unity】3D场景角色血条/状态条

实现方式有很多,看哪种更适合你的项目:

1. UGUI实现

UI可以方便的实现血条等功能,只需要将角色的世界坐标转换为屏幕坐标,让状态条跟随角色即可

问题在于,UI始终在屏幕最上层,如果有3D物体遮挡住角色,使角色不可见,UI状态条仍然可见(暴露玩家位置)

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class UIRoleStatusBar : MonoBehaviour
{
    Camera mainCamera;
    Transform targetRole;

    //允许超出屏幕外偏移量
    int outScreenOffset = 200;
    //跟随速度(差值)
    float followSpeed = 0.25f;
    //相对于角色的偏移量
    Vector3 rolePosOffset = new Vector3(0, 2, 0);

    void Awake()
    {
        mainCamera = Camera.main;
    }

    public void Init(Transform role)
    {
        targetRole = role;
        UpdateBarPos();
    }

    Vector3 tempScreenPos;
    public void UpdateBarPos()
    {
        if (targetRole != null)
        {
            //世界坐标转屏幕坐标
            tempScreenPos = mainCamera.WorldToScreenPoint(targetRole.position + rolePosOffset);

            //如果位置在屏幕范围内,刷新位置
            if (tempScreenPos.x > -outScreenOffset && tempScreenPos.x < Screen.width + outScreenOffset && tempScreenPos.y > -outScreenOffset && tempScreenPos.y < Screen.height + outScreenOffset)
            {
                tempScreenPos.z = 0;
                //差值跟随(防止抖动)
                transform.position = Vector3.Lerp(transform.position, tempScreenPos, followSpeed);
            }
        }
    }

}

2. 每个状态条一个Canvas

将Canvas的渲染模式改为世界坐标,作为角色的子物体,自动跟随角色,实现更为简单

问题在于,场景内角色过多时,Canvas数量也多,还有性能问题

3. 2D Sprite实现

让状态条跟随角色,同时保证Sprite始终朝向相机,即始终朝向屏幕,这样就不会出现3D世界里的血条因角色位移或旋转,与屏幕形成夹角,用Sprite模拟UGUI的Slider效果,实现血条,可以更方便的加一些粒子特效

问题就是用起来没UGUI那么方便

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class SpriteRoleStatusBar : MonoBehaviour
{
    [SerializeField] Transform healthBar;

    Camera mainCamera;
    Transform targetRole;

    Vector3 posOffset = new Vector3(0, 2, 0);
    float followSpeed = 0.25f;

    //记录初始位置
    float healthBarInitPosX;

    void Awake()
    {
        mainCamera = Camera.main;
        healthBarInitPosX = healthBar.localPosition.x;
    }

    void Update()
    {
        if (targetRole != null)
            UpdateBarPos();
    }

    public void Init(Transform role)
    {
        targetRole = role;
        UpdateBarPos();
    }

    Vector3 healthBarPos = Vector3.zero;
    Vector3 healthBarScale = Vector3.one;
    public void OnHealthChanged(float healthPercent)
    {
        if (healthPercent < 0)
            healthPercent = 0;
        if (healthPercent > 1)
            healthPercent = 1;


        //修改位置和缩放,实现血条效果
        healthBarPos.x = healthBarInitPosX * (1 - healthPercent);
        healthBar.localPosition = healthBarPos;

        healthBarScale.x = healthPercent;
        healthBar.localScale = healthBarScale;
    }

    void UpdateBarPos()
    {
        //刷新朝向,始终朝向相机
        transform.forward = mainCamera.transform.forward;
        //刷新位置
        transform.position = Vector3.Lerp(transform.position, targetRole.transform.position + posOffset, followSpeed);
    }

}
发布了104 篇原创文章 · 获赞 74 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/qq_39108767/article/details/102787008