using UnityEngine;
using UnityEngine.UI;
public class Test : MonoBehaviour
{
public GameObject go;//物體
public GameObject targetGo;//目標物體
public Image labelUI_img;//標記UI的Image組件
private float labelUI_HalfWidth;//標記UI一半的寬
private float labelUI_HalfHeight;//標記UI一半的高
private Vector2 v3;//v3的座標
private Vector2 v4;//v4的座標
private void Awake()
{
labelUI_HalfWidth = labelUI_img.GetComponent<RectTransform>().rect.width / 2;
labelUI_HalfHeight = labelUI_img.GetComponent<RectTransform>().rect.height / 2;
}
private void Update()
{
//判斷標記UI的顯示與隱藏
if (IsInView(targetGo.transform.position))
{
labelUI_img.enabled = false;
}
else
{
labelUI_img.enabled = true;
}
//設置標記UI的顯示位置
GetV3AndV4(out v3, out v4);
labelUI_img.transform.localPosition = CalculateCrossPoint(go.transform.position, targetGo.transform.position, v3, v4);
}
/// <summary>
/// 得到v3,v4的值
/// </summary>
private void GetV3AndV4(out Vector2 v3, out Vector2 v4)
{
Vector2 v1 = Camera.main.WorldToScreenPoint(go.transform.position);
Vector2 v2 = Camera.main.WorldToScreenPoint(targetGo.transform.position);
Vector2 offset = v2 - v1;
if (Mathf.Abs(offset.x) > Mathf.Abs(offset.y))
{
if (offset.x > 0)
{
v3 = new Vector2(Screen.width - labelUI_HalfWidth, 0);
v4 = new Vector2(Screen.width - labelUI_HalfWidth, Screen.height);
labelUI_img.transform.rotation = Quaternion.Euler(0, 0, -135);
}
else
{
v3 = new Vector2(0 + labelUI_HalfWidth, 0);
v4 = new Vector2(0 + labelUI_HalfWidth, Screen.height);
labelUI_img.transform.rotation = Quaternion.Euler(0, 0, 45);
}
}
else
{
if (offset.y > 0)
{
v3 = new Vector2(0, Screen.height - labelUI_HalfHeight);
v4 = new Vector2(Screen.width, Screen.height - labelUI_HalfHeight);
labelUI_img.transform.rotation = Quaternion.Euler(0, 0, -40);
}
else
{
v3 = new Vector2(0, 0 + labelUI_HalfHeight);
v4 = new Vector2(Screen.width, 0 + labelUI_HalfHeight);
labelUI_img.transform.rotation = Quaternion.Euler(0, 0, -220);
}
}
}
/// <summary>
/// 給定四個點,求兩條線段的交點(y=a1x+b1,y=a2x+b2)
/// v1,v2是物體與目標物體的位置,v3,v4是屏幕左上,左下,右上,右下中的兩個點
/// </summary>
private Vector2 CalculateCrossPoint(Vector3 v1, Vector3 v2, Vector2 v3, Vector2 v4)
{
v1 = Camera.main.WorldToScreenPoint(v1);
v2 = Camera.main.WorldToScreenPoint(v2);
float a1 = 0, b1 = 0, a2 = 0, b2 = 0;
Vector2 crossPoint = Vector2.zero;
if (v1.x != v2.x)
{
a1 = (v1.y - v2.y) / (v1.x - v2.x);
}
if (v1.y != v2.y)
{
b1 = v1.y - v1.x * (v1.y - v2.y) / (v1.x - v2.x);
}
if (v3.x != v4.x)
{
a2 = (v3.y - v4.y) / (v3.x - v4.x);
}
if (v3.y != v4.y)
{
b2 = v3.y - v3.x * (v3.y - v4.y) / (v3.x - v4.x);
}
if (a1 == a2 && b1 == b2)
{
Debug.LogWarning("兩條線共線,沒有交點");
return Vector2.zero;
}
else if (a1 == a2)
{
Debug.LogWarning("兩條線平行,沒有交點");
return Vector2.zero;
}
else
{
//交點的x和y座標
//(v3與v4需要進行特殊判定處理)
float x = 0;
float y = 0;
if (v3.x == v4.x)
{
if (v3.x == 0)
{
x = 0;
y = b1;
}
else
{
x = v3.x;
y = x * a1 + b1;
}
}
else if (v3.y == v4.y)
{
if (v3.y == 0)
{
y = 0;
x = -b1 / a1;
}
else
{
y = v3.y;
x = (y - b1) / a1;
}
}
else
{
x = (b2 - b1) / (a1 - a2);
y = a1 * (b2 - b1) / (a1 - a2) + b1;
}
//限定x和y的範圍
x = Mathf.Clamp(x, 0, Screen.width);
y = Mathf.Clamp(y, 0, Screen.height);
crossPoint = new Vector2(x, y);
RectTransformUtility.ScreenPointToLocalPointInRectangle(GameObject.Find("Canvas").GetComponent<RectTransform>(),
crossPoint, null, out crossPoint);
return crossPoint;
}
}
/// <summary>
/// 是否在指定相機的視野範圍內
/// </summary>
/// <param name="worldPos">物體世界座標</param>
/// <returns>是否在相機視野範圍內</returns>
public bool IsInView(Vector3 worldPos)
{
Transform camTransform = Camera.main.transform;
Vector2 viewPos = Camera.main.WorldToViewportPoint(worldPos);
//判斷物體是否在相機前面
Vector3 dir = (worldPos - camTransform.position).normalized;
float dot = Vector3.Dot(camTransform.forward, dir);
if (dot > 0 && viewPos.x >= 0 && viewPos.x <= 1 && viewPos.y >= 0 && viewPos.y <= 1)
{
return true;
}
else
{
return false;
}
}
}