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