using System; using System.Collections.Generic; using DG.Tweening; using UnityEngine; public static class UI_PanelExitUtility { private const float FallbackExitDuration = 0.16f; private const float FallbackExitScale = 0.96f; private static readonly HashSet ExitingPanels = new HashSet(); public static bool PlayExitThen(GameObject panel, Action onComplete) { if (panel == null || !panel.activeInHierarchy) { onComplete?.Invoke(); return false; } if (ExitingPanels.Contains(panel)) { return true; } ExitingPanels.Add(panel); bool completed = false; Action safeComplete = () => { if (completed) { return; } completed = true; ExitingPanels.Remove(panel); onComplete?.Invoke(); }; DOVirtual.DelayedCall(2.5f, () => safeComplete(), true); UI_SettingsPanelEnterAnim settingsAnim = panel.GetComponent(); if (settingsAnim != null && settingsAnim.enabled) { settingsAnim.PlayExitThen(safeComplete); return true; } UI_PanelPopupTween popupTween = panel.GetComponent(); if (popupTween != null && popupTween.enabled) { popupTween.PlayExitThen(safeComplete); return true; } return PlayFallbackExitThen(panel, safeComplete); } private static bool PlayFallbackExitThen(GameObject panel, Action onComplete) { RectTransform rect = panel != null ? panel.transform as RectTransform : null; CanvasGroup group = panel != null ? panel.GetComponent() : null; if (rect == null && group == null) { onComplete?.Invoke(); return false; } if (group == null) { group = panel.AddComponent(); } Vector3 baseScale = rect != null ? rect.localScale : Vector3.one; float baseAlpha = group.alpha; float duration = Mathf.Max(0.01f, FallbackExitDuration); bool canScale = rect == null || !UI_OrderedEntryAnimator.IsLayoutSensitive(rect); if (rect != null) { rect.DOKill(); } group.DOKill(); group.interactable = false; group.blocksRaycasts = false; Sequence seq = DOTween.Sequence().SetUpdate(true); if (rect != null && canScale) { seq.Join(rect.DOScale(baseScale * FallbackExitScale, duration).SetEase(Ease.InCubic)); } seq.Join(group.DOFade(0f, duration).SetEase(Ease.InCubic)); bool restored = false; Action restore = () => { if (restored) { return; } restored = true; if (rect != null && canScale) { rect.localScale = baseScale; } if (group != null) { group.alpha = baseAlpha; group.interactable = true; group.blocksRaycasts = true; } }; seq.OnComplete(() => { restore(); onComplete?.Invoke(); }); seq.OnKill(() => restore()); return true; } }