278 lines
6.9 KiB
C#
278 lines
6.9 KiB
C#
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; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// 计算屏幕的位置
|
|
/// </summary>
|
|
|
|
public static Vector3 CalculateScreenPosition(Vector3 position/* 目标点*/, Camera camera, Canvas canvas,
|
|
RectTransform transform)
|
|
{
|
|
|
|
Assert.IsNotNull<Camera>(camera);
|
|
Assert.IsNotNull<Canvas>(canvas);
|
|
Assert.IsNotNull<RectTransform>(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<RectTransform>();
|
|
|
|
if (this.gameCamera == null)
|
|
{
|
|
this.gameCamera = Camera.main;
|
|
}
|
|
|
|
this.UpdatePos();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// 主要调用方法
|
|
/// </summary>
|
|
private void LateUpdate()
|
|
{
|
|
|
|
|
|
if (this.gameCamera == null)
|
|
{
|
|
this.gameCamera = Camera.main;
|
|
}
|
|
UpdatePos();
|
|
|
|
}
|
|
|
|
|
|
private Tween Anim;
|
|
|
|
|
|
/// <summary>
|
|
/// 外部调用方法
|
|
/// </summary>
|
|
/// <param name="isT"> 是否显示</param>
|
|
/// <param name="LiJiWanCheng">是否立即完成</param>
|
|
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显示动画
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// UI隐藏动画
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
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<RectTransform>() );
|
|
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<RectTransform>().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;
|
|
|
|
|
|
|
|
}
|