using UnityEngine;
namespace Watermelon
{
///
/// Core tween engine. Owns all instances and orchestrates
/// tween registration, update routing, pause/resume, and factory helpers.
/// (the MonoBehaviour) is a thin facade that delegates every call here.
///
public class TweenManager
{
private TweensHolder[] holders;
///
/// One per (index 0 = Update, 1 = FixedUpdate, 2 = LateUpdate).
///
public TweensHolder[] Holders => holders;
private TweenCaseCollection activeCollection;
private bool isCollectionEnabled;
///
/// Creates a manager with three instances — one per Unity update loop.
///
/// Initial capacity for tweens.
/// Initial capacity for tweens.
/// Initial capacity for tweens.
public TweenManager(int updateCount, int fixedCount, int lateCount)
{
holders = new TweensHolder[]
{
new TweensHolder(UpdateMethod.Update, updateCount),
new TweensHolder(UpdateMethod.FixedUpdate, fixedCount),
new TweensHolder(UpdateMethod.LateUpdate, lateCount)
};
}
// -----------------------------------------------------------
// Core tween management
// -----------------------------------------------------------
///
/// Registers in the appropriate based on its
/// . If a batch collection is active (see ),
/// the tween is also added to it.
///
public void AddTween(TweenCase tween)
{
holders[tween.UpdateMethodIndex].AddTween(tween);
if (isCollectionEnabled)
activeCollection.AddTween(tween);
}
///
/// Forwards the kill request to the appropriate for deferred removal.
/// Called by .
///
public void MarkForKilling(TweenCase tween)
{
holders[tween.UpdateMethodIndex].MarkForKilling(tween);
}
// -----------------------------------------------------------
// Pause / Resume / Remove
// -----------------------------------------------------------
/// Pauses all tweens running in the specified loop.
public void Pause(UpdateMethod tweenType) => holders[(int)tweenType].Pause();
/// Resumes all tweens running in the specified loop.
public void Resume(UpdateMethod tweenType) => holders[(int)tweenType].Resume();
/// Kills all tweens running in the specified loop.
public void Remove(UpdateMethod tweenType) => holders[(int)tweenType].Kill();
/// Pauses all tweens across every update loop.
public void PauseAll() { foreach (var h in holders) h.Pause(); }
/// Resumes all tweens across every update loop.
public void ResumeAll() { foreach (var h in holders) h.Resume(); }
/// Kills all tweens across every update loop. OnComplete callbacks are not fired.
public void RemoveAll() { foreach (var h in holders) h.Kill(); }
// -----------------------------------------------------------
// Collection batch tracking
// -----------------------------------------------------------
///
/// Starts collecting every subsequently created tween into a new .
/// Call to stop collecting.
///
/// The newly created collection that will receive tweens until is called.
public TweenCaseCollection BeginCollection()
{
isCollectionEnabled = true;
activeCollection = new TweenCaseCollection();
return activeCollection;
}
/// Stops populating the active batch collection. Tweens created after this call are not added to any collection.
public void EndCollection()
{
isCollectionEnabled = false;
activeCollection = null;
}
// -----------------------------------------------------------
// Update — called by Tween MonoBehaviour each Unity event
// -----------------------------------------------------------
/// Drives the holder. Called from MonoBehaviour.Update.
public void UpdateRegular(float dt, float udt) => holders[0].Update(dt, udt);
/// Drives the holder. Called from MonoBehaviour.FixedUpdate.
public void UpdateFixed(float dt, float udt) => holders[1].Update(dt, udt);
/// Drives the holder. Called from MonoBehaviour.LateUpdate.
public void UpdateLate(float dt, float udt) => holders[2].Update(dt, udt);
// -----------------------------------------------------------
// Lifecycle
// -----------------------------------------------------------
///
/// Unloads all holders and resets collection state.
/// Called when the MonoBehaviour is destroyed.
///
public void Unload()
{
foreach (var h in holders)
h.Unload();
activeCollection = null;
isCollectionEnabled = false;
}
// -----------------------------------------------------------
// Factory helpers (mirrors Tween static API)
// -----------------------------------------------------------
///
/// Schedules to be invoked after seconds.
/// Returns null if delay is <= 0 (the callback is invoked immediately instead).
/// Use the .KillActive() extension on the result to safely cancel without a null check.
///
public TweenCase DelayedCall(float delay, SimpleCallback callback, bool unscaledTime = false, UpdateMethod tweenType = UpdateMethod.Update)
{
if (delay <= 0)
{
callback?.Invoke();
return null;
}
return new SystemTweenCases.Default()
.SetDuration(delay)
.SetUnscaledMode(unscaledTime)
.OnComplete(callback)
.SetUpdateMethod(tweenType)
.StartTween();
}
/// Interpolates a value from to over seconds, invoking each frame.
public TweenCase DoColor(Color startValue, Color resultValue, float time, SystemTweenCases.ColorCase.TweenColorCallback callback, bool unscaledTime = false, UpdateMethod tweenType = UpdateMethod.Update)
{
return new SystemTweenCases.ColorCase(startValue, resultValue, callback)
.SetDuration(time)
.SetUnscaledMode(unscaledTime)
.SetUpdateMethod(tweenType)
.StartTween();
}
/// Interpolates a value from to over seconds, invoking each frame.
public TweenCase DoFloat(float startValue, float resultValue, float time, SystemTweenCases.Float.TweenFloatCallback callback, float delay = 0.0f, bool unscaledTime = false, UpdateMethod tweenType = UpdateMethod.Update)
{
return new SystemTweenCases.Float(startValue, resultValue, callback)
.SetDelay(delay)
.SetDuration(time)
.SetUnscaledMode(unscaledTime)
.SetUpdateMethod(tweenType)
.StartTween();
}
///
/// Runs every frame until it calls tweenCase.Complete().
/// Useful for polling conditions that don't have a fixed duration.
///
public TweenCase DoWaitForCondition(SystemTweenCases.Condition.TweenConditionCallback callback, bool unscaledTime = false, UpdateMethod tweenType = UpdateMethod.Update)
{
return new SystemTweenCases.Condition(callback)
.SetDuration(float.MaxValue)
.SetUnscaledMode(unscaledTime)
.SetUpdateMethod(tweenType)
.StartTween();
}
///
/// Invokes after frames have passed.
/// Uses unscaled time by default so it works regardless of Time.timeScale.
///
public TweenCase NextFrame(SimpleCallback callback, int framesOffset = 1, bool unscaledTime = true, UpdateMethod updateMethod = UpdateMethod.Update)
{
return new SystemTweenCases.NextFrame(callback, framesOffset)
.SetDuration(float.MaxValue)
.SetUnscaledMode(unscaledTime)
.SetUpdateMethod(updateMethod)
.StartTween();
}
}
}