using System.Collections.Generic; namespace Watermelon { /// /// Tracks a group of objects and fires a single callback /// when every tween in the group has finished — either by natural completion or by being killed. /// /// Usage patterns: /// /// Manual: create a collection, call for each tween, then . /// Automatic: bracket tween creation with / /// — all tweens created in between are auto-collected. /// Operator: use collection += tween to lazily create and populate a collection. /// /// /// /// Kill-path correctness: /// The collection subscribes to each tween's internal OnTerminated hook, which fires for both /// and . This ensures the /// callback is always invoked regardless of how individual tweens end. /// /// public class TweenCaseCollection { private List tweenCases = new List(); /// All tweens registered in this collection. public List TweenCases => tweenCases; private SimpleCallback tweensCompleted; /// /// Adds to the collection and subscribes to its termination event. /// The termination hook fires for both and . /// public void AddTween(TweenCase tweenCase) { // OnTerminated fires for both Complete() and Kill() — covers all termination paths tweenCase.OnTerminated(OnTweenCaseTerminated); tweenCases.Add(tweenCase); } /// /// Returns true if every tween in the collection is no longer active /// (i.e. all have been completed or killed). An empty collection is considered complete. /// public bool IsComplete() { // IsActive becomes false immediately on Kill() or Complete()->Kill(), so this is the // single reliable "still running" check regardless of how the tween ended. for (int i = 0; i < tweenCases.Count; i++) { if (tweenCases[i].IsActive) return false; } return true; } /// Forces immediate completion of all tweens in the collection (applies final values and fires per-tween callbacks). public void Complete() { for (int i = 0; i < tweenCases.Count; i++) { tweenCases[i].Complete(); } } /// Kills all tweens in the collection. Per-tween OnComplete callbacks are not fired, but the collection's callback is. public void Kill() { for (int i = 0; i < tweenCases.Count; i++) { tweenCases[i].Kill(); } } /// /// Registers a callback to be invoked when all tweens in the collection finish (regardless of whether they complete or are killed). /// Multiple calls accumulate callbacks (+= semantics). /// public void OnComplete(SimpleCallback callback) { tweensCompleted += callback; } /// /// Called by each tween when it terminates. Checks whether all tweens have finished /// and fires if so. /// private void OnTweenCaseTerminated() { for (int i = 0; i < tweenCases.Count; i++) { if (tweenCases[i].IsActive) return; } tweensCompleted?.Invoke(); } /// /// Convenience operator: adds to , /// creating a new collection first if is null. /// /// /// TweenCaseCollection group = null; /// group += transform.DOMove(target, 0.5f); /// group += spriteRenderer.DOFade(0f, 0.5f); /// group.OnComplete(() => Debug.Log("all done")); /// /// /// public static TweenCaseCollection operator +(TweenCaseCollection caseCollection, TweenCase tweenCase) { if(caseCollection == null) caseCollection = new TweenCaseCollection(); caseCollection.AddTween(tweenCase); return caseCollection; } } }