using System; using UnityEngine; using UnityEngine.Assertions; using UnityEngine.UI; using DG.Tweening; /// 提示UI挂载 // [AddComponentMenu("JiaSuQi/UI/Control/UI Follow Target")] [RequireComponent(typeof(RectTransform))] public sealed class UIFollowTarget : MonoBehaviour { public Transform Target { get { return this.target; } set { this.target = value; } } public Canvas Canvas { get { return this.canvas; } set { this.canvas = value; } } public Camera Camera { get { return this.gameCamera; } set { this.gameCamera = value; } } /// /// 计算屏幕的位置 /// public static Vector3 CalculateScreenPosition(Vector3 position/* 目标点*/, Camera camera, Canvas canvas, RectTransform transform) { Assert.IsNotNull(camera); Assert.IsNotNull(canvas); Assert.IsNotNull(transform); //世界坐标转屏幕坐标 Vector3 vector = camera.WorldToScreenPoint(position); Vector3 zero = Vector3.zero; //判断canvas 渲染模式 switch (canvas.renderMode) { //屏幕空间 case RenderMode.ScreenSpaceOverlay: RectTransformUtility.ScreenPointToWorldPointInRectangle(transform, vector, null, out zero); break; case RenderMode.ScreenSpaceCamera: //世界空间 case RenderMode.WorldSpace: RectTransformUtility.ScreenPointToWorldPointInRectangle(transform, vector, canvas.worldCamera, out zero); break; } return zero; } private void Awake() { //获取父物体rectTransForm this.rectTransform = base.GetComponent(); if (this.gameCamera == null) { this.gameCamera = Camera.main; } this.UpdatePos(); } /// /// 主要调用方法 /// private void LateUpdate() { if (this.gameCamera == null) { this.gameCamera = Camera.main; } UpdatePos(); } private Tween Anim; /// /// 外部调用方法 /// /// 是否显示 /// 是否立即完成 public void PlayShowOrClose(bool isT,bool LiJiWanCheng) { if (isT) { if (LiJiWanCheng) { transform.gameObject.SetActive(true); YuanDian.color = new Color(1,1,1,1); zhiyinxian.fillAmount = 1; tip.transform.localScale=Vector3.one; } else { transform.gameObject.SetActive(true); YuanDian.color = new Color(1,1,1,0); zhiyinxian.fillAmount = 0; tip.transform.localScale=Vector3.zero; Anim?.Kill(); Anim = showAnim().Play(); } } else { if (LiJiWanCheng) { YuanDian.color = new Color(1,1,1,0); zhiyinxian.fillAmount = 0; tip.transform.localScale=Vector3.zero; Anim.Kill(); transform.gameObject.SetActive(false); } else { // Debug.Log("UI关闭动画播放中"); YuanDian.color = new Color(1,1,1,1); zhiyinxian.fillAmount = 1; tip.transform.localScale=Vector3.one; Anim?.Kill(); Anim = close().Play(). OnComplete(() => { transform.gameObject.SetActive(false); // Debug.Log("UI关闭动画播放完成"); }); } } } /// UI显示动画 /// /// Tween showAnim() { var sequence= DOTween.Sequence(); var t= YuanDian.DOFade(1, 1.25f); sequence.Insert(0.0f, t); var t1 = zhiyinxian.DOFillAmount(1,ZhiYinXianTime); sequence.Insert(0.2f, t); var t2 = tip.transform.DOScale(Vector3.one, TipTime); sequence.Insert(0.5f, t); return sequence; } /// /// UI隐藏动画 /// /// private Tween close() { var sequence = DOTween.Sequence(); Tween t; t = tip.transform.DOScale(Vector3.zero, 0.2f); sequence.Insert(0, t); t = zhiyinxian.DOFillAmount(0, 0.5f); sequence.Insert(0.5f, t); t = YuanDian.DOFade(0, 1f); sequence.Insert(0.85f, t); return sequence; } private void UpdatePos() { if (this.target == null || this.canvas == null || this.gameCamera == null || this.rectTransform == null) { return; } //计算屏幕坐标 Vector3 position = CalculateScreenPosition(this.target.position, this.gameCamera, this.canvas,tip.GetComponent() ); tip.transform.position = position+tipOffset; YuanDian.transform.position = Camera.WorldToScreenPoint(target.position)+YuanDianOffset; zhiyinxian.transform.position = (YuanDian.transform.position+tip.transform.position)/2; zhiyinxian.transform.localEulerAngles = new Vector3(0, 0, Vector2.SignedAngle(Vector2.right, YuanDian.transform.position- tip.transform.position)); float length = (YuanDian.transform.position-tip.transform.position).magnitude; //设置线的宽度 长度 zhiyinxian. GetComponent().sizeDelta = new Vector2(length, 3f); } [SerializeField,Header("image")] public Image YuanDian; [SerializeField, Header("原点偏移量")] private Vector3 YuanDianOffset; [SerializeField, Header("tip")] private GameObject tip; [SerializeField, Header("提示缩放时间")] private float TipTime; [SerializeField] private Transform target; [SerializeField] private Camera gameCamera; [SerializeField] private Canvas canvas; [SerializeField, Header("指引线UI")] private Image zhiyinxian; [SerializeField, Header("指引线填充时间")] private float ZhiYinXianTime; [SerializeField,Header("tip偏移量")] public Vector3 tipOffset; [SerializeField, Header("text")] public Text Text; private RectTransform rectTransform; }