using DG.Tweening; using UnityEngine; [DisallowMultipleComponent] public class UI_PanelPopupTween : MonoBehaviour { [SerializeField] private RectTransform moveTarget; [SerializeField] private CanvasGroup fadeTarget; [SerializeField] private bool playOnEnable = true; [SerializeField] private float enterDuration = 0.2f; [SerializeField] private float exitDuration = 0.16f; [SerializeField] private float fromOffsetY = 24f; [SerializeField] private float scaleFrom = 0.96f; [SerializeField] private Ease enterEase = Ease.OutCubic; [SerializeField] private Ease exitEase = Ease.InCubic; [SerializeField] private bool useUnscaledTime = true; private Sequence enterSequence; private bool baseCached; private Vector2 basePos; private Vector3 baseScale; private void Awake() { AutoWire(); CacheBaseState(); } private void OnEnable() { if (playOnEnable) { Play(); } } private void OnDisable() { KillTween(); ResetToBase(); } public void Play() { AutoWire(); CacheBaseState(); if (moveTarget == null || fadeTarget == null) { return; } KillTween(); Vector2 fromPos = basePos + new Vector2(0f, -Mathf.Abs(fromOffsetY)); bool canAnimateTransform = !UI_OrderedEntryAnimator.IsLayoutSensitive(moveTarget); if (canAnimateTransform) { moveTarget.anchoredPosition = fromPos; moveTarget.localScale = baseScale * Mathf.Max(0.01f, scaleFrom); } fadeTarget.alpha = 0f; fadeTarget.interactable = false; fadeTarget.blocksRaycasts = false; float duration = Mathf.Max(0.01f, enterDuration); enterSequence = DOTween.Sequence().SetUpdate(useUnscaledTime); if (canAnimateTransform) { enterSequence.Join(moveTarget.DOAnchorPos(basePos, duration).SetEase(enterEase)); enterSequence.Join(moveTarget.DOScale(baseScale, duration).SetEase(enterEase)); } enterSequence.Join(fadeTarget.DOFade(1f, duration).SetEase(Ease.OutCubic)); enterSequence.OnComplete(() => { fadeTarget.interactable = true; fadeTarget.blocksRaycasts = true; enterSequence = null; }); enterSequence.OnKill(() => { ResetToBase(); enterSequence = null; }); } public void PlayExitThen(System.Action onComplete) { AutoWire(); CacheBaseState(); if (moveTarget == null || fadeTarget == null) { onComplete?.Invoke(); return; } KillTween(); fadeTarget.interactable = false; fadeTarget.blocksRaycasts = false; Vector2 targetPos = basePos + new Vector2(0f, -Mathf.Abs(fromOffsetY)); Vector3 targetScale = baseScale * Mathf.Max(0.01f, scaleFrom); float duration = Mathf.Max(0.01f, exitDuration); bool canAnimateTransform = !UI_OrderedEntryAnimator.IsLayoutSensitive(moveTarget); enterSequence = DOTween.Sequence().SetUpdate(useUnscaledTime); if (canAnimateTransform) { enterSequence.Join(moveTarget.DOAnchorPos(targetPos, duration).SetEase(exitEase)); enterSequence.Join(moveTarget.DOScale(targetScale, duration).SetEase(exitEase)); } enterSequence.Join(fadeTarget.DOFade(0f, duration).SetEase(Ease.InCubic)); enterSequence.OnComplete(() => { enterSequence = null; ResetToBase(); onComplete?.Invoke(); }); enterSequence.OnKill(() => { ResetToBase(); enterSequence = null; }); } private void AutoWire() { if (moveTarget == null) { moveTarget = transform as RectTransform; if (moveTarget == null) { moveTarget = GetComponentInChildren(true); } } if (fadeTarget == null) { fadeTarget = GetComponent(); } if (fadeTarget == null) { fadeTarget = gameObject.AddComponent(); } } private void CacheBaseState() { if (moveTarget == null || baseCached) { return; } basePos = moveTarget.anchoredPosition; baseScale = moveTarget.localScale; baseCached = true; } private void ResetToBase() { if (moveTarget != null && baseCached) { if (!UI_OrderedEntryAnimator.IsLayoutSensitive(moveTarget)) { moveTarget.anchoredPosition = basePos; moveTarget.localScale = baseScale; } } if (fadeTarget != null) { fadeTarget.alpha = 1f; fadeTarget.interactable = true; fadeTarget.blocksRaycasts = true; } } private void KillTween() { if (enterSequence != null) { enterSequence.Kill(); enterSequence = null; } if (moveTarget != null) { moveTarget.DOKill(); } if (fadeTarget != null) { fadeTarget.DOKill(); } } }