Code/SbTween/Core/TweenManager.cs
using Sandbox;
using System.Collections.Generic;
using System.Linq;
namespace SbTween;
public sealed class TweenManager : Component, Component.ExecuteInEditor
{
private static TweenManager _instance;
public static TweenManager Instance
{
get
{
var activeScene = Game.ActiveScene;
if ( activeScene == null ) return null;
var found = activeScene.GetAllComponents<TweenManager>().FirstOrDefault();
if ( found.IsValid() )
{
_instance = found;
return found;
}
var go = activeScene.CreateObject();
go.Name = "SbTween_Manager";
go.Flags = GameObjectFlags.NotSaved | GameObjectFlags.Hidden;
_instance = go.Components.Create<TweenManager>();
return _instance;
}
}
// Shoutout Enzo for this fix
public static TweenManager Current => _instance != null && _instance.IsValid ? _instance : null;
private readonly List<BaseTween> _activeTweens = new();
private readonly List<TweenSequence> _activeSequences = new();
public T AddTween<T>( T tween ) where T : BaseTween
{
if ( tween == null ) return null;
if ( !string.IsNullOrEmpty( tween.Id ) )
{
var existing = _activeTweens
.Where( t => t.Id == tween.Id && t != tween )
.ToList();
foreach ( var t in existing )
{
t.Stop();
Log.Warning( "[SbTween] - Tween (" + t.Target + ") won't be played because id: " + t.Id + ", already exists. Use different id for this tween." );
}
}
if ( !_activeTweens.Contains( tween ) ) //If multiple same tweens are on the object it makes them faster and faster.
_activeTweens.Add( tween );
return tween;
}
public void RemoveTween( BaseTween tween )
{
if ( tween == null ) return;
if ( _activeTweens.Contains( tween ) )
{
_activeTweens.Remove( tween );
}
}
public void AddSequence( TweenSequence seq )
{
if ( !_activeSequences.Contains( seq ) )
_activeSequences.Add( seq );
}
protected override void OnUpdate()
{
if ( _activeTweens.Count == 0 && _activeSequences.Count == 0 ) return;
float dt = RealTime.Delta;
bool isAnyTweenMoving = false;
// --- Tweens ---
for ( int i = _activeTweens.Count - 1; i >= 0; i-- )
{
var tween = _activeTweens[i];
if ( tween == null || tween.IsFinished )
{
_activeTweens.RemoveAt( i );
continue;
}
if ( !tween.IsPaused )
{
tween.Update( dt );
isAnyTweenMoving = true;
}
}
// --- Sequences ---
for ( int i = _activeSequences.Count - 1; i >= 0; i-- )
{
var seq = _activeSequences[i];
if ( seq == null || seq.IsFinished )
{
_activeSequences.RemoveAt( i );
continue;
}
seq.Update();
isAnyTweenMoving = true;
}
if ( isAnyTweenMoving && !Game.IsPlaying )
{
foreach ( var tween in _activeTweens )
{
if ( tween.Target.IsValid() )
{
tween.Target.Transform.Local = tween.Target.Transform.Local;
break;
}
}
}
}
// TIMELINE
public void Pause( string id )
{
if ( string.IsNullOrEmpty( id ) ) return;
var targets = _activeTweens.Where( t => t.Id == id ).ToList();
foreach ( var t in targets ) t.Pause();
}
public void Pause( GameObject target )
{
if ( target == null ) return;
var targets = _activeTweens.Where( t => t.Target == target ).ToList();
foreach ( var t in targets ) t.Pause();
}
public void Play( string id )
{
if ( string.IsNullOrEmpty( id ) ) return;
var targets = _activeTweens.Where( t => t.Id == id ).ToList();
foreach ( var t in targets ) t.Play();
}
public void Play( GameObject target )
{
if ( target == null ) return;
var targets = _activeTweens.Where( t => t.Target == target ).ToList();
foreach ( var t in targets ) t.Play();
}
public void Stop( string id )
{
if ( string.IsNullOrEmpty( id ) ) return;
var targets = _activeTweens.Where( t => t.Id == id ).ToList();
foreach ( var t in targets ) t.Stop();
}
public void Stop( GameObject target )
{
if ( target == null ) return;
var targets = _activeTweens.Where( t => t.Target == target ).ToList();
foreach ( var t in targets ) t.Stop();
}
public void KillTweenOnObject( GameObject target, string id )
{
if ( !target.IsValid() || string.IsNullOrEmpty( id ) ) return;
var toKill = _activeTweens
.Where( t => t.Target == target && t.Id == id )
.ToList();
foreach ( var tween in toKill )
{
tween.Kill();
_activeTweens.Remove( tween );
}
}
public void KillAllTweensOnObject( GameObject target )
{
if ( !target.IsValid() ) return;
var toKill = _activeTweens
.Where( t => t.Target == target )
.ToList();
foreach ( var tween in toKill )
{
tween.Kill();
_activeTweens.Remove( tween );
}
}
//THANKS ENZO (damien9709) for fixing this!
public static bool IsInstanceValid()
{
return _instance != null;
}
}