using System; using System.Collections.Generic; using DG.Tweening; using UnityEngine; using UnityEngine.UI; public static class UI_OrderedEntryAnimator { public static Sequence Play( Transform root, float itemDuration, float itemStagger, Vector2 fromOffset, bool useUnscaledTime, Predicate includePredicate = null) { if (root == null) return null; List targets = CollectTargets(root, includePredicate); if (targets.Count == 0) return null; targets.Sort(CompareByTopThenLeft); float duration = Mathf.Max(0.01f, itemDuration); float stagger = Mathf.Max(0f, itemStagger); Sequence sequence = DOTween.Sequence().SetUpdate(useUnscaledTime); for (int i = 0; i < targets.Count; i++) { RectTransform rt = targets[i]; if (rt == null || !rt.gameObject.activeInHierarchy) continue; CanvasGroup group = rt.GetComponent(); if (group == null) group = rt.gameObject.AddComponent(); rt.DOKill(); group.DOKill(); Vector2 basePos = rt.anchoredPosition; float baseAlpha = group.alpha <= 0f ? 1f : group.alpha; rt.anchoredPosition = basePos + fromOffset; group.alpha = 0f; float startAt = i * stagger; sequence.Insert(startAt, rt.DOAnchorPos(basePos, duration).SetEase(Ease.OutCubic).SetUpdate(useUnscaledTime)); sequence.Insert(startAt, group.DOFade(baseAlpha, duration).SetEase(Ease.OutCubic).SetUpdate(useUnscaledTime)); } return sequence; } public static Sequence PlayKeyDownFlash( Transform keyDownRoot, bool useUnscaledTime, float fromYOffset = 36f, float itemStagger = 0.03f) { if (keyDownRoot == null) return null; List targets = CollectKeyDownRects(keyDownRoot); if (targets.Count == 0) return null; targets.Sort(CompareByTopThenLeft); Sequence sequence = DOTween.Sequence().SetUpdate(useUnscaledTime); float moveDuration = 0.1f; float stagger = Mathf.Max(0f, itemStagger); float offsetY = Mathf.Abs(fromYOffset); for (int i = 0; i < targets.Count; i++) { RectTransform rt = targets[i]; if (rt == null || !rt.gameObject.activeInHierarchy) continue; CanvasGroup group = rt.GetComponent(); if (group == null) group = rt.gameObject.AddComponent(); rt.DOKill(); group.DOKill(); Vector2 basePos = rt.anchoredPosition; rt.anchoredPosition = basePos - new Vector2(0f, offsetY); group.alpha = 0f; float startAt = i * stagger; sequence.Insert(startAt, rt.DOAnchorPos(basePos, moveDuration).SetEase(Ease.OutCubic).SetUpdate(useUnscaledTime)); sequence.Insert(startAt, group.DOFade(1f, 0.028f).SetEase(Ease.Linear).SetUpdate(useUnscaledTime)); sequence.Insert(startAt + 0.028f, group.DOFade(0.2f, 0.026f).SetEase(Ease.Linear).SetUpdate(useUnscaledTime)); sequence.Insert(startAt + 0.054f, group.DOFade(1f, 0.04f).SetEase(Ease.OutCubic).SetUpdate(useUnscaledTime)); } return sequence; } public static bool IsNamedOrChildOf(Transform target, string name) { if (target == null || string.IsNullOrEmpty(name)) return false; Transform it = target; while (it != null) { if (string.Equals(it.name, name, StringComparison.OrdinalIgnoreCase)) return true; it = it.parent; } return false; } private static List CollectTargets(Transform root, Predicate includePredicate) { List list = new List(128); HashSet seen = new HashSet(); Stack stack = new Stack(); stack.Push(root); while (stack.Count > 0) { Transform parent = stack.Pop(); if (parent == null) continue; for (int i = 0; i < parent.childCount; i++) { Transform child = parent.GetChild(i); if (child == null) continue; stack.Push(child); RectTransform rt = child as RectTransform; if (rt == null || !child.gameObject.activeInHierarchy) continue; if (includePredicate != null && !includePredicate(rt)) continue; if (!IsPanelLike(child)) continue; if (!seen.Add(rt)) continue; list.Add(rt); } } return list; } private static List CollectKeyDownRects(Transform root) { List list = new List(16); RectTransform[] all = root.GetComponentsInChildren(true); for (int i = 0; i < all.Length; i++) { RectTransform rt = all[i]; if (rt == null || !rt.gameObject.activeInHierarchy) continue; if (rt == root) continue; string n = rt.name ?? string.Empty; if (n.IndexOf("sdw 3", StringComparison.OrdinalIgnoreCase) < 0) continue; list.Add(rt); } return list; } private static bool IsPanelLike(Transform tr) { if (tr == null) return false; if (tr.GetComponent() != null) return true; if (tr.GetComponent() != null) return true; if (tr.GetComponent() != null) return true; if (tr.GetComponent() != null) return true; return tr.childCount > 0; } private static int CompareByTopThenLeft(RectTransform a, RectTransform b) { if (a == null && b == null) return 0; if (a == null) return 1; if (b == null) return -1; Vector3 pa = a.position; Vector3 pb = b.position; int xOrder = pa.x.CompareTo(pb.x); // left -> right if (xOrder != 0) return xOrder; return -pa.y.CompareTo(pb.y); // top -> bottom } }