201 lines
6.6 KiB
C#
201 lines
6.6 KiB
C#
using Sirenix.OdinInspector;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
/// <summary>
|
|
/// 最上层UI_箭头指引
|
|
/// </summary>
|
|
public partial class TopmostLayerUI
|
|
{
|
|
/// <summary>
|
|
/// 边缘间隔
|
|
/// </summary>
|
|
public float edgeSpacing=0.5f;
|
|
|
|
/// <summary>
|
|
/// 箭头指引节点
|
|
/// </summary>
|
|
public Transform arrowheadPointToNode;
|
|
|
|
/// <summary>
|
|
/// 箭头指向的字典
|
|
/// </summary>
|
|
public Dictionary<string, ArrowPoints> arrowPointsDic = new Dictionary<string, ArrowPoints>();
|
|
|
|
/// <summary>
|
|
/// 设置箭头指向
|
|
/// </summary>
|
|
/// <param name="mono">MonoBehaviour类</param>
|
|
/// <param name="name">指向ID</param>
|
|
/// <param name="target">指向的3D对象</param>
|
|
/// <param name="sprite">图标</param>
|
|
public void SetArrowObj(string name, GameObject target, Sprite sprite = null)
|
|
{
|
|
if (this.arrowPointsDic.ContainsKey(name)) return;
|
|
YooAssetManager.Instance.LoadAssetAsync<GameObject>(PackagesName.GameData, "ArrowObj", (arrowObj) =>
|
|
{
|
|
ArrowObjUI arrows =CachePoolManager.Instance.Take(arrowObj).GetComponent<ArrowObjUI>();
|
|
arrows.SetIconImage(sprite);
|
|
arrows.transform.SetParent(arrowheadPointToNode);
|
|
arrows.transform.localPosition = Vector3.zero;
|
|
arrows.transform.localScale = Vector3.one;
|
|
|
|
Coroutine coroutine = StartCoroutine(E_SetPointObj(arrows, target.transform));
|
|
ArrowPoints arrowPoints = new ArrowPoints();
|
|
arrowPoints.coroutine = coroutine;
|
|
arrowPoints.arrowObj = arrows.gameObject;
|
|
|
|
if (!arrowPointsDic.ContainsKey(name))
|
|
{
|
|
arrowPointsDic.Add(name, arrowPoints);
|
|
}
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置箭头指向的协程
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private IEnumerator E_SetPointObj(ArrowObjUI arrows, Transform target)
|
|
{
|
|
Vector3 recordingPos=Vector3.zero;
|
|
arrows.gameObject.SetActive(false);
|
|
while (true)
|
|
{
|
|
if (target)
|
|
{
|
|
var pos = Camera.main.WorldToScreenPoint(target.transform.position);
|
|
var distance = Vector3.Distance(recordingPos, pos);
|
|
if (distance > 1)
|
|
{
|
|
recordingPos = pos;
|
|
if (0 > pos.x || pos.x > Screen.width || pos.y < 0 || pos.y > Screen.height || pos.z < 0)
|
|
{
|
|
arrows.gameObject.SetActive(true);
|
|
|
|
if (pos.z < 0)
|
|
{
|
|
pos = pos * -1;
|
|
}
|
|
|
|
var startpos = new Vector3(Screen.width / 2f, Screen.height / 2f, 0);
|
|
var dir = (pos - startpos).normalized;
|
|
|
|
//通过反余弦函数获取 向量 a、b 夹角(默认为 弧度)
|
|
float radians = Mathf.Atan2(dir.y, dir.x);
|
|
|
|
//将弧度转换为 角度
|
|
float angle = radians * Mathf.Rad2Deg;
|
|
|
|
arrows.transform.localEulerAngles = new Vector3(0, 0, angle);
|
|
|
|
float sereenangle = (float)Screen.height / (float)Screen.width;
|
|
var va = System.Math.Abs(dir.y / dir.x);
|
|
if (va <= sereenangle)
|
|
{
|
|
var length = arrows.GetComponent<RectTransform>().sizeDelta.x;
|
|
if (pos.x < 0)
|
|
{
|
|
arrows.transform.position = GetNodeX(pos, startpos, length * edgeSpacing);
|
|
}
|
|
else
|
|
{
|
|
arrows.transform.position = GetNodeX(pos, startpos, Screen.width - length * edgeSpacing);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var length = arrows.GetComponent<RectTransform>().sizeDelta.x;
|
|
|
|
if (pos.y < 0)
|
|
{
|
|
arrows.transform.position = GetNodeY(pos, startpos, length * edgeSpacing);
|
|
}
|
|
else
|
|
{
|
|
arrows.transform.position = GetNodeY(pos, startpos, Screen.height - length * edgeSpacing);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
arrows.gameObject.SetActive(false);
|
|
}
|
|
}
|
|
}
|
|
yield return null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 计算物体超过屏幕高或小于0时UI的位置
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private Vector3 GetNodeY(Vector3 pos, Vector3 startpos, float v)
|
|
{
|
|
pos = new Vector3(pos.x, pos.y, 0);
|
|
Vector3 ab = pos - startpos;
|
|
Vector3 am = ab * (Mathf.Abs(startpos.y - v) / Mathf.Abs(pos.y - startpos.y));
|
|
Vector3 om = startpos + am;
|
|
return om;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 计算物体超过屏幕宽或小于0时UI的位置
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private Vector3 GetNodeX(Vector3 pos, Vector3 startpos, float v)
|
|
{
|
|
pos = new Vector3(pos.x, pos.y, 0);
|
|
Vector3 ab = pos - startpos;
|
|
Vector3 am = ab * (Mathf.Abs(startpos.x - v) / Mathf.Abs(pos.x - startpos.x));
|
|
Vector3 om = startpos + am;
|
|
return om;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 指定关闭
|
|
/// </summary>
|
|
/// <param name="name"></param>
|
|
public void SpecifyClose(string name)
|
|
{
|
|
if (arrowPointsDic.ContainsKey(name))
|
|
{
|
|
StopCoroutine(arrowPointsDic[name].coroutine);
|
|
Destroy(arrowPointsDic[name].arrowObj);
|
|
arrowPointsDic.Remove(name);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 全部关闭
|
|
/// </summary>
|
|
[Button]
|
|
public void Clear()
|
|
{
|
|
foreach (var item in arrowPointsDic)
|
|
{
|
|
StopCoroutine(arrowPointsDic[item.Key].coroutine);
|
|
Destroy(arrowPointsDic[item.Key].arrowObj);
|
|
}
|
|
arrowPointsDic.Clear();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 指向对象
|
|
/// </summary>
|
|
public class ArrowPoints
|
|
{
|
|
/// <summary>
|
|
/// 指向的协程
|
|
/// </summary>
|
|
public Coroutine coroutine;
|
|
|
|
/// <summary>
|
|
/// 指向问题的UI
|
|
/// </summary>
|
|
public GameObject arrowObj;
|
|
}
|