欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

3D场景角色血条/状态条

程序员文章站 2022-03-26 23:20:11
...

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

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);
    }

}