因为场景中相机和ui所示相机为两个相机,所以需要将坐标从场景相机转换到ui相机中
using UnityEngine;
public class ArrowItem3D : MonoBehaviour
{
private Camera m_sceneCamera;
private Camera m_uiCamera;
private Canvas m_canvas;
private GameObject m_playerObj;
private GameObject m_targetObj;
private Vector3 m_playerVec;
private Vector3 m_targetVec;
private static float MAX_SIZE_DISTANCE = 50f;
private static float MAX_SCALE = 0.5f;
public void Init(GameObject player, GameObject target, Canvas canvas, Camera sceneCamera,Camera uiCamera)
{
m_playerObj = player;
m_targetObj = target;
m_canvas = canvas;
m_sceneCamera = sceneCamera;
m_uiCamera = uiCamera;
}
private void Update()
{
UpdateItemPos();
}
/// <summary>
/// 旋转,位置,并且scale也有变化
/// </summary>
private void UpdateItemPos()
{
m_targetVec = m_targetObj.transform.position;
m_playerVec = m_playerObj.transform.position;
//旋转
Vector3 tmp = SceneWorldToUIWorld(m_targetVec) - SceneWorldToUIWorld(m_playerVec);
transform.up = tmp;
var dist = tmp.magnitude;
float scale = dist > MAX_SIZE_DISTANCE ? 1 : Mathf.Max(MAX_SCALE, dist / MAX_SIZE_DISTANCE);
transform.localScale = new Vector3(scale, scale, 1);
//pos
Vector3 uiTargetPos = SceneWorldToUIWorld(m_targetVec);
transform.position = uiTargetPos;
Vector3 uiTargetLocalPos = transform.localPosition;
//具体的逻辑 根据分辨率确定屏幕UI坐标系的边界
float screenScale = m_canvas.GetComponent<RectTransform>().rect.width / m_canvas.GetComponent<RectTransform>().rect.height;
float uiHeight = m_canvas.GetComponent<RectTransform>().rect.height;
float uiWidth = m_canvas.GetComponent<RectTransform>().rect.width;
float screenHeight = uiHeight / 2;
float screenWidth = uiWidth / 2;
if (Mathf.Abs(uiTargetLocalPos.y) <= screenHeight && Mathf.Abs(uiTargetLocalPos.x) <= screenWidth)
{
return;
}
if (uiTargetLocalPos.y == 0)
{
float posX = uiTargetLocalPos.x > 0 ? screenWidth : screenWidth * -1;
this.transform.localPosition = new Vector3(posX, 0, 0);
return;
}
if (uiTargetLocalPos.x == 0)
{
float posY = uiTargetLocalPos.y > 0 ? screenHeight : screenHeight * -1;
this.transform.localPosition = new Vector3(0, posY, 0);
return;
}
float targetScale = uiTargetLocalPos.x / uiTargetLocalPos.y;
//大于的话以横屏为标准
if (Mathf.Abs(targetScale) > screenScale)
{
float width = uiTargetLocalPos.x > 0 ? screenWidth : -1 * screenWidth;
this.transform.localPosition = new Vector3(width, width / targetScale, 0);
}
else
{
float height = uiTargetLocalPos.y > 0 ? screenHeight : -1 * screenHeight;
this.transform.localPosition = new Vector3(height * targetScale, height, 0);
}
}
/// <summary>
/// 场景相机世界坐标系转ui相机世界坐标系
/// </summary>
/// <param name="pos"></param>
/// <returns></returns>
private Vector3 SceneWorldToUIWorld(Vector3 pos)
{
Vector3 vec = m_sceneCamera.WorldToScreenPoint(pos);
if (Vector3.Dot(m_sceneCamera.transform.forward, pos - m_sceneCamera.transform.position) < 0)
{
vec = -vec;
}
vec.z = m_canvas.planeDistance;
return m_uiCamera.ScreenToWorldPoint(vec);
}
}