using UnityEngine;
using System.Collections;
namespace Watermelon
{
///
/// MonoBehaviour facade for the tween system.
/// Hosts Unity lifecycle hooks (Update / FixedUpdate / LateUpdate) and coroutine support.
/// All state and logic lives in ; this class is intentionally thin.
///
/// Usage: call once (typically from ), then use
/// the static extension methods on Unity objects (e.g. transform.DOMove(...)) or the static
/// factory helpers (, , etc.).
///
public class Tween : MonoBehaviour
{
private static Tween instance;
private static TweenManager manager;
///
/// Direct access to the underlying array (indexed by ).
/// Primarily used by tests and advanced tooling; prefer the static API for normal usage.
///
public static TweensHolder[] Tweens => manager?.Holders;
///
/// Initialises the tween system with pre-allocated arrays for each Unity update loop.
/// Must be called exactly once before any tweens are created (done automatically by ).
///
/// Initial capacity for tweens.
/// Initial capacity for tweens.
/// Initial capacity for tweens.
public void Init(int tweensUpdateCount, int tweensFixedUpdateCount, int tweensLateUpdateCount)
{
instance = this;
manager = new TweenManager(tweensUpdateCount, tweensFixedUpdateCount, tweensLateUpdateCount);
// DontDestroyOnLoad is only valid in Play Mode.
// Edit Mode tests (NUnit) skip this without affecting runtime behaviour.
if (Application.isPlaying)
DontDestroyOnLoad(gameObject);
}
// -----------------------------------------------------------
// Unity lifecycle — delegate to manager
// -----------------------------------------------------------
private void Update() => manager?.UpdateRegular(Time.deltaTime, Time.unscaledDeltaTime);
private void FixedUpdate() => manager?.UpdateFixed(Time.fixedDeltaTime, Time.fixedUnscaledDeltaTime);
private void LateUpdate() => manager?.UpdateLate(Time.deltaTime, Time.unscaledDeltaTime);
private void OnDestroy()
{
manager?.Unload();
manager = null;
instance = null;
}
// -----------------------------------------------------------
// Static facade — all delegate to manager
// -----------------------------------------------------------
/// Registers a tween with the system. Called internally by .
public static void AddTween(TweenCase tween) => manager?.AddTween(tween);
/// Enqueues a tween for deferred removal. Called internally by .
public static void MarkForKilling(TweenCase tween) => manager?.MarkForKilling(tween);
/// Pauses all tweens in the specified update loop.
public static void Pause(UpdateMethod tweenType) => manager?.Pause(tweenType);
/// Pauses all active tweens across every update loop.
public static void PauseAll() => manager?.PauseAll();
/// Resumes all tweens in the specified update loop.
public static void Resume(UpdateMethod tweenType) => manager?.Resume(tweenType);
/// Resumes all paused tweens across every update loop.
public static void ResumeAll() => manager?.ResumeAll();
/// Kills all tweens in the specified update loop.
public static void Remove(UpdateMethod tweenType) => manager?.Remove(tweenType);
/// Kills all active tweens across every update loop. OnComplete callbacks are not fired.
public static void RemoveAll() => manager?.RemoveAll();
///
/// Immediately clears all tweens and resets internal state without destroying the MonoBehaviour or its manager.
/// Use this before scene reloads instead of — defers cleanup
/// to the next Update, which can cause index errors if new tweens are added before that update runs.
///
public static void KillAll() => manager?.Unload();
///
/// Begins collecting every subsequently created tween into a single .
/// Call to stop collecting.
///
/// The collection that will receive all tweens started before is called.
public static TweenCaseCollection BeginTweenCaseCollection() => manager?.BeginCollection();
/// Stops populating the active batch collection started by .
public static void EndTweenCaseCollection() => manager?.EndCollection();
///
/// Schedules to be invoked after seconds.
/// Returns null if <= 0 (the callback is invoked immediately instead).
/// Use the .KillActive() extension on the result to safely cancel without a null check.
///
public static TweenCase DelayedCall(float delay, SimpleCallback callback, bool unscaledTime = false, UpdateMethod tweenType = UpdateMethod.Update)
=> manager?.DelayedCall(delay, callback, unscaledTime, tweenType);
/// Interpolates a value and invokes each frame.
public static TweenCase DoColor(Color startValue, Color resultValue, float time, SystemTweenCases.ColorCase.TweenColorCallback callback, bool unscaledTime = false, UpdateMethod tweenType = UpdateMethod.Update)
=> manager?.DoColor(startValue, resultValue, time, callback, unscaledTime, tweenType);
/// Interpolates a value and invokes each frame.
public static TweenCase DoFloat(float startValue, float resultValue, float time, SystemTweenCases.Float.TweenFloatCallback callback, float delay = 0.0f, bool unscaledTime = false, UpdateMethod tweenType = UpdateMethod.Update)
=> manager?.DoFloat(startValue, resultValue, time, callback, delay, unscaledTime, tweenType);
///
/// Runs every frame until it calls tweenCase.Complete().
/// Useful for polling a condition without a fixed duration.
///
public static TweenCase DoWaitForCondition(SystemTweenCases.Condition.TweenConditionCallback callback, bool unscaledTime = false, UpdateMethod tweenType = UpdateMethod.Update)
=> manager?.DoWaitForCondition(callback, unscaledTime, tweenType);
///
/// Invokes after frames have elapsed.
/// Uses unscaled time by default so it fires regardless of Time.timeScale.
///
public static TweenCase NextFrame(SimpleCallback callback, int framesOffset = 1, bool unscaledTime = true, UpdateMethod updateMethod = UpdateMethod.Update)
=> manager?.NextFrame(callback, framesOffset, unscaledTime, updateMethod);
/// Starts a coroutine on the MonoBehaviour, allowing non-MonoBehaviour scripts to run coroutines.
public static Coroutine InvokeCoroutine(IEnumerator enumerator)
{
if (instance == null) return null;
return instance.StartCoroutine(enumerator);
}
/// Stops a coroutine previously started via .
public static void StopCustomCoroutine(Coroutine coroutine)
{
if (instance == null) return;
instance.StopCoroutine(coroutine);
}
/// Stops all coroutines and unloads all tween holders. Used for manual cleanup (e.g. before scene reload).
public static void DestroyObject()
{
if (instance != null)
instance.StopAllCoroutines();
manager?.Unload();
}
}
}