最近有一个需求是仿照原神的地图在屏幕边界显示任务和人物的追踪指引。
具体思路:
因为地图上的任务和人物图标本身就是UI,可以通过Transform.TransformPoint将对应的任务和人物图标转换为世界坐标,再通过Transform.InverseTransformPoint将世界坐标转换为本地坐标,这两个方法需要保证层级的正确。
下面是代码:
/// <summary>
/// 边界追踪
/// </summary>
/// <param name="vector">追踪目标坐标</param>
void EdgeTracking(Vector3 vector)
{
/// m_Trans 追踪目标UI的父级
/// m_Panel 边缘指引UI的父级
/// m_Tracking 边缘指引UI
/// ui_Screen_Width/ui_Screen_Height UI的屏幕分辨率
/// defaultAspectRatio ui的宽高比
var worldPos = m_Trans.TransformPoint(m_Point.anchoredPosition);
var nowPos = m_Panel.InverseTransformPoint(worldPos);
if (Mathf.Abs(nowPos.x) > ui_Screen_Width || Mathf.Abs(nowPos.y) > ui_Screen_Height)
{
var currentAspectRatio = Mathf.Abs(nowPos.x) / Mathf.Abs(nowPos.y);
var currentPos = Vector2.zero;
if (currentAspectRatio > defaultAspectRatio)
{
var valueX = nowPos.x / Mathf.Abs(nowPos.x) * ui_Screen_Width;
currentPos = new Vector2(valueX, nowPos.y * Mathf.Abs(valueX / nowPos.x));
}
else
{
var valueY = nowPos.y / Mathf.Abs(nowPos.y) * ui_Screen_Height;
currentPos = new Vector2(nowPos.x * Mathf.Abs(valueY / nowPos.y), valueY);
}
m_Tracking.anchoredPosition = currentPos;
m_Tracking.localEulerAngles = new Vector3(0, 0, Mathf.Atan2(currentPos.y, currentPos.x) * Mathf.Rad2Deg);
}
}