前言:
近期因为需要制作玩家和敌人头顶的2D血条,查找了很多博客,发现很多都拘束于Canvas的渲染模式必须要设定为ScreenSpace-Overlay,还有应该是版本原因(我的是unity2019.1.11f1)用RecttTransform.position
去获得赋值,而不用anchoredPosition的疑惑;
思路:把角色身上的血条位置转化为屏幕坐标,赋值给血条UI
实现:获得血条的放置位置,可以在玩家或敌人预制体来预作血条节点,通过Camera.main.WorldToViewportPoint()得到视窗坐标,这一步是为了解决角色消失在视野之外,而血条还在视野内;通过Camera.main.WorldToScreenPoint()得到屏幕坐标,赋值给血条UI即可;
1.设置Canvas,这是我的Canvas的RenderMode和UI ScaleMode的选择
需要注意的是Scale With Screen Size屏幕自适应性,等下计算屏幕坐标你需要用到缩放因子ScaleFactor
如果不是很清楚Render Mode 和UI Scale Mode建议先了解
2.代码实现:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class hpCanvas : MonoBehaviour
{
private RectTransform Hprect; //UI血条
private Transform Target; //需要血条的目标玩家/敌人
private Canvas canvas; //UI血条的根节点Canvas
private Vector3 Head_topPos = Vector3.zero; //血条节点坐标
private Vector2 screenPos = Vector2.zero; //转换得到的屏幕坐标
private void Start()
{
Hprect = GameObject.Find("HpBar").GetComponent<RectTransform>();
Target = GameObject.FindGameObjectWithTag("Player").transform;
canvas = Hprect.transform.parent.GetComponent<Canvas>();
}
private void Update()
{
if (Target == null) return;
Head_topPos = Target.Find("head_top").transform.position;
var viewPos = Camera.main.WorldToViewportPoint(Head_topPos);//得到视窗坐标
if (viewPos.z > 0f && viewPos.x > 0f && viewPos.x < 1f && viewPos.y > 0f && viewPos.y < 1f)
{
screenPos = Camera.main.WorldToScreenPoint(Head_topPos) * 1f / canvas.scaleFactor;
}
else
{
screenPos = Vector3.up * 3000f;//目标不在视野内,把它移到视野之外
}
Hprect.anchoredPosition = screenPos;//为血条UI的坐标赋值
}
}
3.代码解释:
HpCanvas脚本是放任意物体上都可,为了方便在Start里我直接使用GameObject.Find,当然这种方式不好,你们可以通过public直接拖拽,因为UI Scale Mode我选的是Scale With Screen Size,所以当屏幕缩放后你需要相应的乘以缩放因子1f / canvas.scaleFactor;