Added GTWeen

This commit is contained in:
Marco 2025-02-24 11:52:50 +01:00
commit 2036e4e748
152 changed files with 5889 additions and 7 deletions

View file

@ -0,0 +1,169 @@
using System;
using GTweens.TweenBehaviours;
using GTweens.Tweens;
namespace GTweens.Builders;
/// <summary>
/// Builder class for creating sequences of tweens.
/// </summary>
public sealed class GTweenSequenceBuilder
{
readonly SequenceTweenBehaviour _sequenceTweenBehaviour;
readonly GTween _gTween;
bool _creatingGroupTween;
GroupTweenBehaviour? _groupTweenBehaviour;
GTweenSequenceBuilder()
{
_sequenceTweenBehaviour = new SequenceTweenBehaviour();
_gTween = new GTween(_sequenceTweenBehaviour);
}
/// <summary>
/// Creates a new instance of the <see cref="GTweenSequenceBuilder"/>.
/// </summary>
/// <returns>A new instance of the builder.</returns>
public static GTweenSequenceBuilder New()
{
return new GTweenSequenceBuilder();
}
/// <summary>
/// Adds the given tween to the end of the Sequence. This tween will play after all the previous tweens have finished.
/// </summary>
/// <param name="gTween">The GTween to append to the sequence.</param>
/// <returns>The current instance of the builder.</returns>
public GTweenSequenceBuilder Append(GTween gTween)
{
_creatingGroupTween = false;
_sequenceTweenBehaviour.Add(gTween);
return this;
}
/// <summary>
/// Inserts the given tween at the same time position of the last tween added to the Sequence.
/// This tween will play at the same time as the previous tween.
/// </summary>
/// <param name="gTween">The GTween to join with the sequence.</param>
/// <returns>The current instance of the builder.</returns>
public GTweenSequenceBuilder Join(GTween gTween)
{
if (_creatingGroupTween)
{
_groupTweenBehaviour!.Add(gTween);
return this;
}
_creatingGroupTween = true;
_groupTweenBehaviour = new GroupTweenBehaviour();
if (_sequenceTweenBehaviour.Tweens.Count > 0)
{
GTween previousTween = _sequenceTweenBehaviour.Tweens[^1];
_sequenceTweenBehaviour.Remove(previousTween);
_groupTweenBehaviour.Add(previousTween);
}
_groupTweenBehaviour.Add(gTween);
_sequenceTweenBehaviour.Add(new GTween(_groupTweenBehaviour));
return this;
}
/// <summary>
/// Appends a callback action to the end of the sequence.
/// </summary>
/// <param name="callback">The callback action to append.</param>
/// <param name="callIfCompletingInstantly">Whether to call the callback if the tween is asked to complete instantly.</param>
/// <returns>The current instance of the builder.</returns>
public GTweenSequenceBuilder AppendCallback(Action callback, bool callIfCompletingInstantly = true)
{
CallbackTweenBehaviour callbackTweenBehaviour = new(callback, callIfCompletingInstantly);
Append(new GTween(callbackTweenBehaviour));
return this;
}
/// <summary>
/// Inserts the given callback at the same time position of the last tween added to the Sequence.
/// This tween will play at the same time as the previous tween.
/// </summary>
/// <param name="callback">The callback action to append.</param>
/// <param name="callIfCompletingInstantly">Whether to call the callback if the tween is asked to complete instantly.</param>
/// <returns>The current instance of the builder.</returns>
public GTweenSequenceBuilder JoinCallback(Action callback, bool callIfCompletingInstantly = true)
{
CallbackTweenBehaviour callbackTweenBehaviour = new(callback, callIfCompletingInstantly);
Join(new GTween(callbackTweenBehaviour));
return this;
}
/// <summary>
/// Appends a time delay to the end of the sequence.
/// </summary>
/// <param name="timeSeconds">The duration of the time delay in seconds.</param>
/// <returns>The current instance of the builder.</returns>
public GTweenSequenceBuilder AppendTime(float timeSeconds)
{
WaitTimeTweenBehaviour timeTweenBehaviour = new(timeSeconds);
Append(new GTween(timeTweenBehaviour));
return this;
}
/// <summary>
/// Inserts the given time delay at the same time position of the last tween added to the Sequence.
/// This tween will play at the same time as the previous tween.
/// </summary>
/// <param name="timeSeconds">The duration of the time delay in seconds.</param>
/// <returns>The current instance of the builder.</returns>
public GTweenSequenceBuilder JoinTime(float timeSeconds)
{
WaitTimeTweenBehaviour timeTweenBehaviour = new(timeSeconds);
Join(new GTween(timeTweenBehaviour));
return this;
}
/// <summary>
/// Provides a new GTweenSequenceBuilder for building a sequence, and then adds it to the end of the sequence.
/// </summary>
/// <param name="createSequence">An action that defines the nested sequence using a new GTweenSequenceBuilder.</param>
/// <returns>The current instance of the builder.</returns>
public GTweenSequenceBuilder AppendSequence(Action<GTweenSequenceBuilder> createSequence)
{
GTweenSequenceBuilder sequenceBuilder = New();
createSequence.Invoke(sequenceBuilder);
Append(sequenceBuilder.Build());
return this;
}
/// <summary>
/// Provides a new GTweenSequenceBuilder for building a sequence, and then inserts it
/// at the same time position of the last tween added to the Sequence.
/// </summary>
/// <param name="createSequence">An action that defines the nested sequence using a new GTweenSequenceBuilder.</param>
/// <returns>The current instance of the builder.</returns>
public GTweenSequenceBuilder JoinSequence(Action<GTweenSequenceBuilder> createSequence)
{
GTweenSequenceBuilder sequenceBuilder = New();
createSequence.Invoke(sequenceBuilder);
Join(sequenceBuilder.Build());
return this;
}
/// <summary>
/// Builds and returns the final GTween representing the sequence.
/// </summary>
/// <returns>The GTween representing the built sequence.</returns>
public GTween Build() => _gTween;
}

View file

@ -0,0 +1 @@
uid://bt2o7k0sblp2r

View file

@ -0,0 +1,114 @@
using System.Collections.Generic;
using System.Diagnostics;
using GTweens.Tweens;
namespace GTweens.Contexts
{
/// <summary>
/// Manages and updates a collection of GTweens.
/// </summary>
public sealed class GTweensContext
{
/// <summary>
/// Gets or sets the time scale at which the tweens should play.
/// </summary>
public float TimeScale { get; set; } = 1f;
/// <summary>
/// Gets the duration of the last tweens tick in milliseconds.
/// </summary>
public float TickDurationMs { get; private set; }
readonly List<GTween> _aliveTweens = new();
readonly List<GTween> _tweensToAdd = new();
readonly List<GTween> _tweensToRemove = new();
readonly Stopwatch _updateStopwatch = new();
/// <summary>
/// Plays a GTween within the context.
/// </summary>
/// <param name="gTween">The GTween to play.</param>
public void Play(GTween gTween)
{
if(gTween.IsNested)
{
return;
}
if(gTween.IsAlive)
{
TryStartTween(gTween);
return;
}
gTween.IsAlive = true;
_tweensToAdd.Add(gTween);
TryStartTween(gTween);
}
/// <summary>
/// Updates the context and all managed tweens.
/// </summary>
/// <param name="deltaTime">The elapsed time since the last update in seconds.</param>
public void Tick(float deltaTime)
{
float scaledDeltaTime = deltaTime * TimeScale;
_updateStopwatch.Restart();
foreach(GTween tween in _tweensToAdd)
{
_aliveTweens.Add(tween);
}
_tweensToAdd.Clear();
foreach (GTween tween in _aliveTweens)
{
if(tween.IsPlaying)
{
tween.Tick(scaledDeltaTime);
}
else
{
_tweensToRemove.Add(tween);
}
}
foreach(GTween tween in _tweensToRemove)
{
tween.IsAlive = false;
_aliveTweens.Remove(tween);
_tweensToAdd.Remove(tween);
}
_tweensToRemove.Clear();
_updateStopwatch.Stop();
TickDurationMs = _updateStopwatch.ElapsedMilliseconds;
}
/// <summary>
/// Clears all tweens from the context.
/// </summary>
public void Clear()
{
_aliveTweens.Clear();
_tweensToAdd.Clear();
_tweensToRemove.Clear();
}
void TryStartTween(GTween gTween)
{
if (!gTween.IsPlaying)
{
gTween.Start();
}
}
}
}

View file

@ -0,0 +1 @@
uid://cc0xhrqaeyj2a

View file

@ -0,0 +1,6 @@
namespace GTweens.Delegates;
public static class ValidationDelegates
{
public delegate bool Validation();
}

View file

@ -0,0 +1 @@
uid://dgm5i26rfdj1t

View file

@ -0,0 +1,37 @@
namespace GTweens.Easings
{
public enum Easing
{
Linear,
InSine,
OutSine,
InOutSine,
InQuad,
OutQuad,
InOutQuad,
InCubic,
OutCubic,
InOutCubic,
InQuart,
OutQuart,
InOutQuart,
InQuint,
OutQuint,
InOutQuint,
InExpo,
OutExpo,
InOutExpo,
InCirc,
OutCirc,
InOutCirc,
InBack,
OutBack,
InOutBack,
InElastic,
OutElastic,
InOutElastic,
InBounce,
OutBounce,
InOutBounce
}
}

View file

@ -0,0 +1 @@
uid://h86tmt5twtn8

View file

@ -0,0 +1,4 @@
namespace GTweens.Easings
{
public delegate float EasingDelegate(float a, float b, float t);
}

View file

@ -0,0 +1 @@
uid://d3yvf3ck512ig

View file

@ -0,0 +1,239 @@
using System;
namespace GTweens.Easings
{
public static class PresetEasingDelegateFactory
{
const float C1 = 1.70158f;
const float C2 = C1 * 1.525f;
const float C3 = C1 + 1;
const float C4 = (2 * (float)Math.PI) / 3;
const float C5 = (2 * (float)Math.PI) / 4.5f;
const float N1 = 7.5625f;
const float D1 = 2.75f;
public static EasingDelegate GetEaseDelegate(Easing easing)
{
EasingDelegate result;
switch (easing)
{
default:
case Easing.Linear: result = Linear; break;
case Easing.InSine: result = InSine; break;
case Easing.OutSine: result = OutSine; break;
case Easing.InOutSine: result = InOutSine; break;
case Easing.InQuad: result = InQuad; break;
case Easing.OutQuad: result = OutQuad; break;
case Easing.InOutQuad: result = InOutQuad; break;
case Easing.InCubic: result = InCubic; break;
case Easing.OutCubic: result = OutCubic; break;
case Easing.InOutCubic: result = InOutCubic; break;
case Easing.InQuart: result = InQuart; break;
case Easing.OutQuart: result = OutQuart; break;
case Easing.InOutQuart: result = InOutQuart; break;
case Easing.InQuint: result = InQuint; break;
case Easing.OutQuint: result = OutQuint; break;
case Easing.InOutQuint: result = InOutQuint; break;
case Easing.InExpo: result = InExpo; break;
case Easing.OutExpo: result = OutExpo; break;
case Easing.InOutExpo: result = InOutExpo; break;
case Easing.InCirc: result = InCirc; break;
case Easing.OutCirc: result = OutCirc; break;
case Easing.InOutCirc: result = InOutCirc; break;
case Easing.InBack: result = InBack; break;
case Easing.OutBack: result = OutBack; break;
case Easing.InOutBack: result = InOutBack; break;
case Easing.InElastic: result = InElastic; break;
case Easing.OutElastic: result = OutElastic; break;
case Easing.InOutElastic: result = InOutElastic; break;
case Easing.InBounce: result = InBounce; break;
case Easing.OutBounce: result = OutBounce; break;
case Easing.InOutBounce: result = InOutBounce; break;
}
return result;
}
static float Linear(float a, float b, float t)
{
return Lerp(a, b, t);
}
static float InSine(float a, float b, float t)
{
return Lerp(a, b, 1 - (float)Math.Cos((t * (float)Math.PI) / 2f));
}
static float OutSine(float a, float b, float t)
{
return Lerp(a, b, (float)Math.Sin((t * (float)Math.PI) / 2f));
}
static float InOutSine(float a, float b, float t)
{
return Lerp(a, b, -((float)Math.Cos(t * (float)Math.PI) - 1) / 2f);
}
static float InQuad(float a, float b, float t)
{
return Lerp(a, b, t * t);
}
static float OutQuad(float a, float b, float t)
{
return Lerp(a, b, 1 - (1 - t) * (1 - t));
}
static float InOutQuad(float a, float b, float t)
{
return Lerp(a, b, t < 0.5f ? 2 * t * t : 1 - (float)Math.Pow(-2 * t + 2, 2) / 2);
}
static float InCubic(float a, float b, float t)
{
return Lerp(a, b, t * t * t);
}
static float OutCubic(float a, float b, float t)
{
return Lerp(a, b, 1 - (float)Math.Pow(1 - t, 3));
}
static float InOutCubic(float a, float b, float t)
{
return Lerp(a, b, t < 0.5f ? 4 * t * t * t : 1 -(float) Math.Pow(-2 * t + 2, 3) / 2);
}
static float InQuart(float a, float b, float t)
{
return Lerp(a, b, t * t * t * t);
}
static float OutQuart(float a, float b, float t)
{
return Lerp(a, b, 1 - (float)Math.Pow(1 - t, 4));
}
static float InOutQuart(float a, float b, float t)
{
return Lerp(a, b, t < 0.5f ? 8 * t * t * t * t : 1 - (float)Math.Pow(-2 * t + 2, 4) / 2);
}
static float InQuint(float a, float b, float t)
{
return Lerp(a, b, t * t * t * t * t);
}
static float OutQuint(float a, float b, float t)
{
return Lerp(a, b, 1 - (float)Math.Pow(1 - t, 5));
}
static float InOutQuint(float a, float b, float t)
{
return Lerp(a, b, t < 0.5f ? 16 * t * t * t * t * t : 1 - (float)Math.Pow(-2 * t + 2, 5) / 2);
}
static float InExpo(float a, float b, float t)
{
return Lerp(a, b, t == 0 ? 0 : (float)Math.Pow(2, 10 * t - 10));
}
static float OutExpo(float a, float b, float t)
{
return Lerp(a, b, t == 1 ? 1 : 1 - (float)Math.Pow(2, -10 * t));
}
static float InOutExpo(float a, float b, float t)
{
return Lerp(a, b, t == 0 ? 0 : t == 1 ? 1 : t < 0.5f ? (float)Math.Pow(2, 20 * t - 10) / 2 : (2 - (float)Math.Pow(2, -20 * t + 10)) / 2);
}
static float InCirc(float a, float b, float t)
{
return Lerp(a, b, 1 - (float)Math.Sqrt(1 - (float)Math.Pow(t, 2)));
}
static float OutCirc(float a, float b, float t)
{
return Lerp(a, b, (float)Math.Sqrt(1 - (float)Math.Pow(t - 1, 2)));
}
static float InOutCirc(float a, float b, float t)
{
return Lerp(a, b, t < 0.5f ? (1 - (float)Math.Sqrt(1 - (float)Math.Pow(2 * t, 2))) / 2 : (float)(Math.Sqrt(1 - Math.Pow(-2 * t + 2, 2)) + 1) / 2);
}
static float InBack(float a, float b, float t)
{
return Lerp(a, b, C3 * t * t * t - C1 * t * t);
}
static float OutBack(float a, float b, float t)
{
return Lerp(a, b, 1 + C3 * (float)Math.Pow(t - 1, 3) + C1 * (float)Math.Pow(t - 1, 2));
}
static float InOutBack(float a, float b, float t)
{
return Lerp(a, b, t < 0.5f ? ((float)Math.Pow(2 * t, 2) * ((C2 + 1) * 2 * t - C2)) / 2 : ((float)Math.Pow(2 * t - 2, 2) * ((C2 + 1) * (t * 2 - 2) + C2) + 2) / 2);
}
static float InElastic(float a, float b, float t)
{
return Lerp(a, b, t == 0 ? 0 : t == 1 ? 1 : -(float)Math.Pow(2, 10 * t - 10) * (float)Math.Sin((t * 10 - 10.75f) * C4));
}
static float OutElastic(float a, float b, float t)
{
return Lerp(a, b, t == 0 ? 0 : t == 1 ? 1 : (float)Math.Pow(2, -10 * t) * (float)Math.Sin((t * 10 - 0.75f) * C4) + 1);
}
static float InOutElastic(float a, float b, float t)
{
return Lerp(a, b, t == 0 ? 0 : t == 1 ? 1 : t < 0.5f ? -((float)Math.Pow(2, 20 * t - 10) * (float)Math.Sin((20 * t - 11.125f) * C5)) / 2 : ((float)Math.Pow(2, -20 * t + 10) * (float)Math.Sin((20 * t - 11.125f) * C5)) / +1);
}
static float InBounce(float a, float b, float t)
{
return Lerp(a, b, 1 - RawOutBounce(1 - t));
}
static float OutBounce(float a, float b, float t)
{
return Lerp(a, b, RawOutBounce(t));
}
static float InOutBounce(float a, float b, float t)
{
return Lerp(a, b, t < 0.5f ? (1 - RawOutBounce(1 - 2 * t)) / 2 : (1 + RawOutBounce(2 * t - 1)) / 2);
}
static float RawOutBounce(float t)
{
if (t < 1 / D1)
{
return N1 * t * t;
}
if (t < 2 / D1)
{
return N1 * (t -= 1.5f / D1) * t + 0.75f;
}
if (t < 2.5f / D1)
{
return N1 * (t -= 2.25f / D1) * t + 0.9375f;
}
return N1 * (t -= 2.625f / D1) * t + 0.984375f;
}
static float Lerp(float a, float b, float t)
{
return a + (b - a) * t;
}
}
}

View file

@ -0,0 +1 @@
uid://b70204re20wwk

View file

@ -0,0 +1,28 @@
namespace GTweens.Enums
{
/// <summary>
/// Specifies different modes for resetting the values of a tween animation.
/// </summary>
public enum ResetMode
{
/// <summary>
/// Resets the values to their initial state, as they were when the tween animation started.
/// </summary>
InitialValues,
/// <summary>
/// Resets the values by using the difference between initial and final values, effectively incrementing the new initial and final values.
/// </summary>
IncrementalValues,
/// <summary>
/// Each time reverses the animation initial and final values, in a ping-pong fashion.
/// </summary>
PingPong,
/// <summary>
/// Leaves the values unchanged, maintaining their current state.
/// </summary>
CurrentValues,
}
}

View file

@ -0,0 +1 @@
uid://rg4640a2ekfw

View file

@ -0,0 +1,18 @@
namespace GTweens.Enums
{
/// <summary>
/// Specifies different rotation modes for tweening operations.
/// </summary>
public enum RotationMode
{
/// <summary>
/// Rotates objects using the shortest distance between the initial and final angles.
/// </summary>
ShortestDistance,
/// <summary>
/// Rotates objects based on the total angular distance, which may involve multiple rotations.
/// </summary>
TotalDistance,
}
}

View file

@ -0,0 +1 @@
uid://rnjfaov7hxcd

View file

@ -0,0 +1,87 @@
using System;
using System.Numerics;
using GTweens.Enums;
namespace GTweens.Extensions
{
internal static class AngleExtensions
{
public static float Clamp360(float eulerAngles)
{
float result = eulerAngles - (float)Math.Ceiling(eulerAngles / 360f) * 360f;
if (result < 0)
{
result += 360f;
}
return result;
}
public static Vector3 Clamp360(Vector3 eulerAngles)
{
return new Vector3(
Clamp360(eulerAngles.X),
Clamp360(eulerAngles.Y),
Clamp360(eulerAngles.Z)
);
}
/// <summary>
/// Calculates the shortest difference between two given angles.
/// </summary>
public static float DeltaAngle(float current, float target)
{
float difference = target - current;
float delta = MathExtensions.Repeat(difference, 360f);
if (delta > 180.0F)
{
delta -= 360.0F;
}
return delta;
}
public static Vector3 DeltaAngle(Vector3 current, Vector3 target)
{
return new Vector3(
DeltaAngle(current.X, target.X),
DeltaAngle(current.Y, target.Y),
DeltaAngle(current.Z, target.Z)
);
}
public static float GetDestinationAngleDegrees(float origin, float destination, RotationMode mode)
{
switch(mode)
{
case RotationMode.ShortestDistance:
{
float clampedOrigin = Clamp360(origin);
float clampedDestination = Clamp360(destination);
float deltaAngle = DeltaAngle(clampedOrigin, clampedDestination);
return origin + deltaAngle;
}
default:
case RotationMode.TotalDistance:
{
return destination;
}
}
}
public static float GetDestinationAngleRadiants(float origin, float destination, RotationMode mode)
{
return GetDestinationAngleDegrees(
origin * MathExtensions.Rad2Deg,
destination * MathExtensions.Rad2Deg,
mode
) * MathExtensions.Deg2Rad;
}
}
}

View file

@ -0,0 +1 @@
uid://boj44m1nwtj83

View file

@ -0,0 +1,298 @@
using System.Drawing;
using System.Numerics;
using System.Threading;
using System.Threading.Tasks;
using GTweens.Delegates;
using GTweens.TweenBehaviours;
using GTweens.Tweeners;
using GTweens.Tweens;
namespace GTweens.Extensions
{
public static class GTweenExtensions
{
public static GTween Tween(
Tweener<int>.Getter getter,
Tweener<int>.Setter setter,
Tweener<int>.Getter to,
float duration,
ValidationDelegates.Validation validation
)
{
InterpolationTweenBehaviour tweenBehaviour = new InterpolationTweenBehaviour();
tweenBehaviour.Add(new IntTweener(getter, setter, to, duration, validation));
return new GTween(tweenBehaviour);
}
public static GTween Tween(
Tweener<int>.Getter getter,
Tweener<int>.Setter setter,
int to,
float duration,
ValidationDelegates.Validation validation
) => Tween(getter, setter, () => to, duration, validation);
public static GTween Tween(
Tweener<int>.Getter getter,
Tweener<int>.Setter setter,
int to,
float duration
) => Tween(getter, setter, () => to, duration, ValidationExtensions.AlwaysValid);
public static GTween Tween(
Tweener<float>.Getter getter,
Tweener<float>.Setter setter,
Tweener<float>.Getter to,
float duration,
ValidationDelegates.Validation validation
)
{
InterpolationTweenBehaviour tweenBehaviour = new InterpolationTweenBehaviour();
tweenBehaviour.Add(new FloatTweener(getter, setter, to, duration, validation));
return new GTween(tweenBehaviour);
}
public static GTween Tween(
Tweener<float>.Getter getter,
Tweener<float>.Setter setter,
float to,
float duration,
ValidationDelegates.Validation validation
) => Tween(getter, setter, () => to, duration, validation);
public static GTween Tween(
Tweener<float>.Getter getter,
Tweener<float>.Setter setter,
float to,
float duration
) => Tween(getter, setter, to, duration, ValidationExtensions.AlwaysValid);
public static GTween Tween(
Tweener<Vector2>.Getter getter,
Tweener<Vector2>.Setter setter,
Tweener<Vector2>.Getter to,
float duration,
ValidationDelegates.Validation validation
)
{
InterpolationTweenBehaviour tweenBehaviour = new InterpolationTweenBehaviour();
tweenBehaviour.Add(new SystemVector2Tweener(getter, setter, to, duration, validation));
return new GTween(tweenBehaviour);
}
public static GTween Tween(
Tweener<Vector2>.Getter getter,
Tweener<Vector2>.Setter setter,
Vector2 to,
float duration,
ValidationDelegates.Validation validation
) => Tween(getter, setter, () => to, duration, validation);
public static GTween Tween(
Tweener<Vector2>.Getter getter,
Tweener<Vector2>.Setter setter,
Vector2 to,
float duration
) => Tween(getter, setter, to, duration, ValidationExtensions.AlwaysValid);
public static GTween Tween(
Tweener<Vector3>.Getter getter,
Tweener<Vector3>.Setter setter,
Tweener<Vector3>.Getter to,
float duration,
ValidationDelegates.Validation validation
)
{
InterpolationTweenBehaviour tweenBehaviour = new InterpolationTweenBehaviour();
tweenBehaviour.Add(new SystemVector3Tweener(getter, setter, to, duration, validation));
return new GTween(tweenBehaviour);
}
public static GTween Tween(
Tweener<Vector3>.Getter getter,
Tweener<Vector3>.Setter setter,
Vector3 to,
float duration,
ValidationDelegates.Validation validation
) => Tween(getter, setter, () => to, duration, validation);
public static GTween Tween(
Tweener<Vector3>.Getter getter,
Tweener<Vector3>.Setter setter,
Vector3 to,
float duration
) => Tween(getter, setter, to, duration, ValidationExtensions.AlwaysValid);
public static GTween Tween(
Tweener<Vector4>.Getter getter,
Tweener<Vector4>.Setter setter,
Tweener<Vector4>.Getter to,
float duration,
ValidationDelegates.Validation validation
)
{
InterpolationTweenBehaviour tweenBehaviour = new InterpolationTweenBehaviour();
tweenBehaviour.Add(new SystemVector4Tweener(getter, setter, to, duration, validation));
return new GTween(tweenBehaviour);
}
public static GTween Tween(
Tweener<Vector4>.Getter getter,
Tweener<Vector4>.Setter setter,
Vector4 to,
float duration,
ValidationDelegates.Validation validation
) => Tween(getter, setter, () => to, duration, validation);
public static GTween Tween(
Tweener<Vector4>.Getter getter,
Tweener<Vector4>.Setter setter,
Vector4 to,
float duration
) => Tween(getter, setter, to, duration, ValidationExtensions.AlwaysValid);
public static GTween Tween(
Tweener<Color>.Getter getter,
Tweener<Color>.Setter setter,
Tweener<Color>.Getter to,
float duration,
ValidationDelegates.Validation validation
)
{
InterpolationTweenBehaviour tweenBehaviour = new InterpolationTweenBehaviour();
tweenBehaviour.Add(new SystemColorTweener(getter, setter, to, duration, validation));
return new GTween(tweenBehaviour);
}
public static GTween Tween(
Tweener<Color>.Getter getter,
Tweener<Color>.Setter setter,
Color to,
float duration,
ValidationDelegates.Validation validation
) => Tween(getter, setter, () => to, duration, validation);
public static GTween Tween(
Tweener<Color>.Getter getter,
Tweener<Color>.Setter setter,
Color to,
float duration
) => Tween(getter, setter, to, duration, ValidationExtensions.AlwaysValid);
public static GTween Tween(
Tweener<Quaternion>.Getter getter,
Tweener<Quaternion>.Setter setter,
Tweener<Quaternion>.Getter to,
float duration,
ValidationDelegates.Validation validation
)
{
InterpolationTweenBehaviour tweenBehaviour = new InterpolationTweenBehaviour();
tweenBehaviour.Add(new SystemQuaternionTweener(getter, setter, to, duration, validation));
return new GTween(tweenBehaviour);
}
public static GTween Tween(
Tweener<Quaternion>.Getter getter,
Tweener<Quaternion>.Setter setter,
Quaternion to,
float duration,
ValidationDelegates.Validation validation
) => Tween(getter, setter, () => to, duration, validation);
public static GTween Tween(
Tweener<Quaternion>.Getter getter,
Tweener<Quaternion>.Setter setter,
Quaternion to,
float duration
) => Tween(getter, setter, to, duration, ValidationExtensions.AlwaysValid);
public static GTween Tween(
int from,
int to,
Tweener<int>.Setter setter,
float duration
)
{
return Tween(
() => from,
setter,
to,
duration,
ValidationExtensions.AlwaysValid
);
}
public static GTween Tween(
float from,
float to,
Tweener<float>.Setter setter,
float duration
)
{
return Tween(
() => from,
setter,
to,
duration,
ValidationExtensions.AlwaysValid
);
}
public static GTween TweenTimeScale(this GTween target, float to, float duration)
{
return Tween(
() => target.TimeScale,
current => target.SetTimeScale(current),
to,
duration
);
}
public static bool IsPlayingOrCompleted(this GTween gTween)
{
return gTween.IsPlaying || gTween.IsCompleted;
}
public static bool IsPlayingOrCompletedOrNested(this GTween gTween)
{
return gTween.IsPlaying || gTween.IsCompleted || gTween.IsNested;
}
/// <summary>
/// Asynchronously waits for the completion of a GTween animation or cancellation through a CancellationToken.
/// </summary>
/// <param name="gTween">The GTween instance to monitor for completion.</param>
/// <param name="cancellationToken">The CancellationToken that can be used to cancel the operation.</param>
/// <returns>
/// A Task that represents the asynchronous operation. The Task completes when the GTween animation is complete,
/// or when the CancellationToken is signaled for cancellation.
/// </returns>
public static Task AwaitCompleteOrKill(this GTween gTween, CancellationToken cancellationToken)
{
TaskCompletionSource taskCompletionSource = new();
if (!gTween.IsPlaying)
{
return Task.CompletedTask;
}
if (cancellationToken.IsCancellationRequested)
{
return Task.CompletedTask;
}
void OnCompleteOrKill()
{
gTween.OnCompleteOrKillAction -= OnCompleteOrKill;
taskCompletionSource.TrySetResult();
}
cancellationToken.Register(OnCompleteOrKill);
gTween.OnCompleteOrKill(OnCompleteOrKill);
return taskCompletionSource.Task;
}
}
}

View file

@ -0,0 +1 @@
uid://dei0hda724u2a

View file

@ -0,0 +1,27 @@
using System;
namespace GTweens.Extensions;
public static class MathExtensions
{
public const float Deg2Rad = 0.01745329f;
public const float Rad2Deg = 57.29578f;
public static float SafeDivide(float v1, float v2)
{
if (v2 == 0f)
{
return 0f;
}
return v1 / v2;
}
/// <summary>
/// Loops the value t, so that it is never larger than length and never smaller than 0.
/// </summary>
public static float Repeat(float t, float length)
{
return Math.Clamp(t - (float)Math.Floor(t / length) * length, 0.0f, length);
}
}

View file

@ -0,0 +1 @@
uid://bouwnkbl68u6a

View file

@ -0,0 +1,17 @@
using System.Drawing;
namespace GTweens.Extensions
{
public static class SystemColorExtensions
{
public static Color FromRgba(float r, float g, float b, float a)
{
return Color.FromArgb(
(int)(a * 255f),
(int)(r * 255f),
(int)(g * 255f),
(int)(b * 255f)
);
}
}
}

View file

@ -0,0 +1 @@
uid://cftquavd2ss24

View file

@ -0,0 +1,8 @@
using GTweens.Delegates;
namespace GTweens.Extensions;
public static class ValidationExtensions
{
public static readonly ValidationDelegates.Validation AlwaysValid = () => true;
}

View file

@ -0,0 +1 @@
uid://yer2h7qavcpt

View file

@ -0,0 +1,34 @@
using GTweens.Easings;
namespace GTweens.Interpolators
{
public sealed class FloatInterpolator : IInterpolator<float>
{
public static readonly FloatInterpolator Instance = new();
FloatInterpolator()
{
}
public float Evaluate(
float initialValue,
float finalValue,
float time,
EasingDelegate easingDelegate
)
{
return easingDelegate(initialValue, finalValue, time);
}
public float Subtract(float initialValue, float finalValue)
{
return finalValue - initialValue;
}
public float Add(float initialValue, float finalValue)
{
return finalValue + initialValue;
}
}
}

View file

@ -0,0 +1 @@
uid://b3m1wga6bh0qn

View file

@ -0,0 +1,37 @@
using GTweens.Easings;
namespace GTweens.Interpolators
{
/// <summary>
/// Represents an interpolator for working with transitions between two values of type <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">The type of values to interpolate.</typeparam>
public interface IInterpolator<T>
{
/// <summary>
/// Evaluates the intermediate value between the initial and final values based on the specified time and easing function.
/// </summary>
/// <param name="initialValue">The initial value.</param>
/// <param name="finalValue">The final value.</param>
/// <param name="time">The interpolation time (usually between 0 and 1).</param>
/// <param name="easingFunction">The easing function to apply during interpolation.</param>
/// <returns>The interpolated value between <paramref name="initialValue"/> and <paramref name="finalValue"/>.</returns>
T Evaluate(T initialValue, T finalValue, float time, EasingDelegate easingFunction);
/// <summary>
/// Subtracts two values of type <typeparamref name="T"/>.
/// </summary>
/// <param name="initialValue">The initial value.</param>
/// <param name="finalValue">The final value.</param>
/// <returns>The result of subtracting <paramref name="finalValue"/> from <paramref name="initialValue"/>.</returns>
T Subtract(T initialValue, T finalValue);
/// <summary>
/// Adds two values of type <typeparamref name="T"/>.
/// </summary>
/// <param name="initialValue">The initial value.</param>
/// <param name="finalValue">The final value.</param>
/// <returns>The result of adding <paramref name="finalValue"/> to <paramref name="initialValue"/>.</returns>
T Add(T initialValue, T finalValue);
}
}

View file

@ -0,0 +1 @@
uid://83qvtsiku48u

View file

@ -0,0 +1,34 @@
using GTweens.Easings;
namespace GTweens.Interpolators
{
public sealed class IntInterpolator : IInterpolator<int>
{
public static readonly IntInterpolator Instance = new();
IntInterpolator()
{
}
public int Evaluate(
int initialValue,
int finalValue,
float time,
EasingDelegate easingDelegate
)
{
return (int)easingDelegate(initialValue, finalValue, time);
}
public int Subtract(int initialValue, int finalValue)
{
return finalValue - initialValue;
}
public int Add(int initialValue, int finalValue)
{
return finalValue + initialValue;
}
}
}

View file

@ -0,0 +1 @@
uid://e1vtsq83j4g6

View file

@ -0,0 +1,51 @@
using System.Drawing;
using GTweens.Easings;
using GTweens.Extensions;
namespace GTweens.Interpolators
{
public sealed class SystemColorInterpolator : IInterpolator<Color>
{
public static readonly SystemColorInterpolator Instance = new();
SystemColorInterpolator()
{
}
public Color Evaluate(
Color initialValue,
Color finalValue,
float time,
EasingDelegate easingDelegate
)
{
return SystemColorExtensions.FromRgba(
easingDelegate!(initialValue.A, finalValue.A, time),
easingDelegate(initialValue.R, finalValue.R, time),
easingDelegate(initialValue.G, finalValue.G, time),
easingDelegate(initialValue.B, finalValue.B, time)
);
}
public Color Subtract(Color initialValue, Color finalValue)
{
return Color.FromArgb(
finalValue.A - initialValue.A,
finalValue.R - initialValue.R,
finalValue.G - initialValue.G,
finalValue.B - initialValue.B
);
}
public Color Add(Color initialValue, Color finalValue)
{
return Color.FromArgb(
finalValue.A + initialValue.A,
finalValue.R + initialValue.R,
finalValue.G + initialValue.G,
finalValue.B + initialValue.B
);
}
}
}

View file

@ -0,0 +1 @@
uid://bthivyns1lr7a

View file

@ -0,0 +1,37 @@
using System.Numerics;
using GTweens.Easings;
namespace GTweens.Interpolators
{
public sealed class SystemQuaternionInterpolator : IInterpolator<Quaternion>
{
public static readonly SystemQuaternionInterpolator Instance = new();
SystemQuaternionInterpolator()
{
}
public Quaternion Evaluate(
Quaternion initialValue,
Quaternion finalValue,
float time,
EasingDelegate easingDelegate
)
{
float curveTime = easingDelegate(0f, 1f, time);
return Quaternion.Slerp(initialValue, finalValue, curveTime);
}
public Quaternion Subtract(Quaternion initialValue, Quaternion finalValue)
{
return Quaternion.Inverse(initialValue) * finalValue;
}
public Quaternion Add(Quaternion initialValue, Quaternion finalValue)
{
return initialValue * finalValue;
}
}
}

View file

@ -0,0 +1 @@
uid://d2onw3tx1lfu7

View file

@ -0,0 +1,38 @@
using System.Numerics;
using GTweens.Easings;
namespace GTweens.Interpolators
{
public sealed class SystemVector2Interpolator : IInterpolator<Vector2>
{
public static readonly SystemVector2Interpolator Instance = new();
SystemVector2Interpolator()
{
}
public Vector2 Evaluate(
Vector2 initialValue,
Vector2 finalValue,
float time,
EasingDelegate easingDelegate
)
{
return new Vector2(
easingDelegate(initialValue.X, finalValue.X, time),
easingDelegate(initialValue.Y, finalValue.Y, time)
);
}
public Vector2 Subtract(Vector2 initialValue, Vector2 finalValue)
{
return finalValue - initialValue;
}
public Vector2 Add(Vector2 initialValue, Vector2 finalValue)
{
return finalValue + initialValue;
}
}
}

View file

@ -0,0 +1 @@
uid://dvtde4b3gjv32

View file

@ -0,0 +1,39 @@
using System.Numerics;
using GTweens.Easings;
namespace GTweens.Interpolators
{
public sealed class SystemVector3Interpolator : IInterpolator<Vector3>
{
public static readonly SystemVector3Interpolator Instance = new();
SystemVector3Interpolator()
{
}
public Vector3 Evaluate(
Vector3 initialValue,
Vector3 finalValue,
float time,
EasingDelegate easingDelegate
)
{
return new Vector3(
easingDelegate(initialValue.X, finalValue.X, time),
easingDelegate(initialValue.Y, finalValue.Y, time),
easingDelegate(initialValue.Z, finalValue.Z, time)
);
}
public Vector3 Subtract(Vector3 initialValue, Vector3 finalValue)
{
return finalValue - initialValue;
}
public Vector3 Add(Vector3 initialValue, Vector3 finalValue)
{
return finalValue + initialValue;
}
}
}

View file

@ -0,0 +1 @@
uid://cdm8j104f7hgo

View file

@ -0,0 +1,54 @@
// using Juce.Tweening.Easing;
// using Juce.Tweening.Utils;
// using System;
// using System.Numerics;
//
// namespace Juce.Tweening.Interpolators
// {
// public class SystemVector3RotationInterpolator : IInterpolator<Vector3>
// {
// readonly RotationMode rotationMode;
//
// public SystemVector3RotationInterpolator(RotationMode rotationMode)
// {
// this.rotationMode = rotationMode;
// }
//
// public Vector3 Evaluate(
// Vector3 initialValue,
// Vector3 finalValue,
// float time,
// EaseDelegate easeFunction
// )
// {
// if (easeFunction == null)
// {
// throw new ArgumentNullException($"Tried to Evaluate with a " +
// $"null {nameof(EaseDelegate)} on {nameof(SystemVector3Interpolator)}");
// }
//
// if (rotationMode == RotationMode.Fast)
// {
// Vector3 deltaAngle = AngleUtils.DeltaAngle(initialValue, finalValue);
//
// finalValue = initialValue + deltaAngle;
// }
//
// return new Vector3(
// easeFunction(initialValue.X, finalValue.X, time),
// easeFunction(initialValue.Y, finalValue.Y, time),
// easeFunction(initialValue.Z, finalValue.Z, time)
// );
// }
//
// public Vector3 Subtract(Vector3 initialValue, Vector3 finalValue)
// {
// return finalValue - initialValue;
// }
//
// public Vector3 Add(Vector3 firstValue, Vector3 secondValue)
// {
// return secondValue + firstValue;
// }
// }
// }

View file

@ -0,0 +1 @@
uid://c8hpkxetb6uyg

View file

@ -0,0 +1,40 @@
using System.Numerics;
using GTweens.Easings;
namespace GTweens.Interpolators
{
public sealed class SystemVector4Interpolator : IInterpolator<Vector4>
{
public static readonly SystemVector4Interpolator Instance = new();
SystemVector4Interpolator()
{
}
public Vector4 Evaluate(
Vector4 initialValue,
Vector4 finalValue,
float time,
EasingDelegate easingDelegate
)
{
return new Vector4(
easingDelegate(initialValue.X, finalValue.X, time),
easingDelegate(initialValue.Y, finalValue.Y, time),
easingDelegate(initialValue.Z, finalValue.Z, time),
easingDelegate(initialValue.W, finalValue.W, time)
);
}
public Vector4 Subtract(Vector4 initialValue, Vector4 finalValue)
{
return finalValue - initialValue;
}
public Vector4 Add(Vector4 initialValue, Vector4 finalValue)
{
return finalValue + initialValue;
}
}
}

View file

@ -0,0 +1 @@
uid://cmwi4emxwsy8c

View file

@ -0,0 +1,38 @@
using System;
using GTweens.Enums;
namespace GTweens.TweenBehaviours
{
public sealed class CallbackTweenBehaviour : TweenBehaviour
{
readonly Action _action;
readonly bool _callIfCompletingInstantly;
public CallbackTweenBehaviour(Action action, bool callIfCompletingInstantly)
{
_action = action;
_callIfCompletingInstantly = callIfCompletingInstantly;
}
public override void Start(bool isCompletingInstantly)
{
bool canCall = !isCompletingInstantly || _callIfCompletingInstantly;
if (canCall)
{
_action?.Invoke();
}
MarkFinished();
}
public override void Reset(bool kill, ResetMode loopResetMode)
{
MarkUnfinished();
}
public override float GetDuration() => 0f;
public override float GetElapsed() => 0f;
public override bool GetLoopable() => false;
}
}

View file

@ -0,0 +1 @@
uid://b4nvwfr8t2hvu

View file

@ -0,0 +1,166 @@
using System.Collections.Generic;
using GTweens.Easings;
using GTweens.Enums;
using GTweens.Extensions;
using GTweens.Tweens;
namespace GTweens.TweenBehaviours
{
public sealed class GroupTweenBehaviour : TweenBehaviour
{
public IReadOnlyList<GTween> Tweens => _tweens;
readonly List<GTween> _tweens = new();
readonly List<GTween> _playingTweens = new();
bool _durationCalculated;
float _cachedCalculatedDuration;
public override void Start(bool isCompletingInstantly)
{
StartTweens(isCompletingInstantly);
}
public override void Tick(float deltaTime)
{
for (int i = _playingTweens.Count - 1; i >= 0; --i)
{
GTween gTween = _playingTweens[i];
gTween.Tick(deltaTime);
if (!gTween.IsPlaying)
{
_playingTweens.RemoveAt(i);
}
}
if (_playingTweens.Count == 0)
{
MarkFinished();
}
}
public override void Kill()
{
foreach (GTween tween in _playingTweens)
{
tween.Kill();
}
_playingTweens.Clear();
MarkFinished();
}
public override void Complete()
{
foreach (GTween tween in _playingTweens)
{
if (tween.IsCompleted)
{
continue;
}
if (!tween.IsPlaying)
{
tween.Start(isCompletingInstantly: true);
}
tween.Complete();
}
_playingTweens.Clear();
MarkFinished();
}
public override void Reset(bool kill, ResetMode resetMode)
{
for (int i = _tweens.Count - 1; i >= 0; --i)
{
GTween gTween = _tweens[i];
gTween.Reset(kill, resetMode);
}
MarkUnfinished();
}
public override void SetEasing(EasingDelegate easingFunction)
{
foreach (GTween tween in _tweens)
{
tween.SetEasing(easingFunction);
}
}
public override float GetDuration()
{
if(_durationCalculated)
{
return _cachedCalculatedDuration;
}
_durationCalculated = true;
_cachedCalculatedDuration = 0.0f;
foreach (GTween tween in _tweens)
{
_cachedCalculatedDuration += tween.GetDuration();
}
return _cachedCalculatedDuration;
}
public override float GetElapsed()
{
float totalDuration = 0.0f;
foreach (GTween tween in _tweens)
{
totalDuration += tween.GetElapsed();
}
return totalDuration;
}
public void Add(GTween gTween)
{
if(gTween.IsPlayingOrCompletedOrNested())
{
return;
}
gTween.IsNested = true;
_tweens.Add(gTween);
_durationCalculated = false;
}
void StartTweens(bool isCompletingInstantly)
{
_playingTweens.Clear();
_playingTweens.AddRange(_tweens);
for (int i = _playingTweens.Count - 1; i >= 0; --i)
{
GTween gTween = _playingTweens[i];
gTween.Start(isCompletingInstantly);
if (!gTween.IsPlaying)
{
_playingTweens.RemoveAt(i);
}
}
if (_playingTweens.Count == 0)
{
MarkFinished();
}
}
}
}

View file

@ -0,0 +1 @@
uid://b0sfk7ps1fav6

View file

@ -0,0 +1,22 @@
using GTweens.Easings;
using GTweens.Enums;
namespace GTweens.TweenBehaviours;
public interface ITweenBehaviour
{
float GetDuration();
float GetElapsed();
float GetRemaining();
bool GetLoopable();
void Start(bool isCompletingInstantly);
void Tick(float deltaTime);
void Kill();
void Complete();
void Reset(bool kill, ResetMode loopResetMode);
void SetEasing(EasingDelegate easingFunction);
bool GetFinished();
}

View file

@ -0,0 +1 @@
uid://ceieq47mwyq5q

View file

@ -0,0 +1,173 @@
using System;
using System.Collections.Generic;
using GTweens.Easings;
using GTweens.Enums;
using GTweens.Tweeners;
namespace GTweens.TweenBehaviours
{
public sealed class InterpolationTweenBehaviour : TweenBehaviour
{
readonly List<ITweener> _tweeners = new();
readonly List<ITweener> _playingTweeners = new();
bool _durationCalculated;
float _cachedCalculatedDuration;
public override void Start(bool isCompletingInstantly)
{
StartTweeners();
}
public override void Tick(float deltaTime)
{
for (int i = _playingTweeners.Count - 1; i >= 0; --i)
{
ITweener tweener = _playingTweeners[i];
tweener.Tick(deltaTime);
if (!tweener.IsPlaying)
{
_playingTweeners.RemoveAt(i);
}
}
if (_playingTweeners.Count == 0)
{
MarkFinished();
}
}
public override void Kill()
{
foreach (ITweener tweener in _playingTweeners)
{
tweener.Kill();
}
_playingTweeners.Clear();
MarkFinished();
}
public override void Complete()
{
foreach (ITweener tweener in _playingTweeners)
{
if (!tweener.IsPlaying)
{
continue;
}
tweener.Complete();
}
_playingTweeners.Clear();
MarkFinished();
}
public override void Reset(bool kill, ResetMode resetMode)
{
for (int i = _tweeners.Count - 1; i >= 0; --i)
{
ITweener tweener = _tweeners[i];
tweener.Reset(resetMode);
}
MarkUnfinished();
}
public override void SetEasing(EasingDelegate easingFunction)
{
foreach (ITweener tweener in _tweeners)
{
tweener.SetEasing(easingFunction);
}
}
public override float GetDuration()
{
if(_durationCalculated)
{
return _cachedCalculatedDuration;
}
_durationCalculated = true;
_cachedCalculatedDuration = 0.0f;
foreach (ITweener tweener in _tweeners)
{
_cachedCalculatedDuration += tweener.Duration;
}
return _cachedCalculatedDuration;
}
public override float GetElapsed()
{
float totalElapsed = 0.0f;
foreach (ITweener tweener in _tweeners)
{
totalElapsed += tweener.Elapsed;
}
return totalElapsed;
}
public void Add(ITweener tweener)
{
if (tweener == null)
{
throw new ArgumentNullException(
$"Tried to {nameof(Add)} a null {nameof(ITweener)} on {nameof(InterpolationTweenBehaviour)}"
);
}
if (tweener.IsPlaying)
{
throw new ArgumentNullException(
$"Tried to {nameof(Add)} a {nameof(ITweener)} on {nameof(InterpolationTweenBehaviour)} but it was already playing"
);
}
if (_tweeners.Contains(tweener))
{
throw new ArgumentNullException(
$"Tried to {nameof(Add)} a {nameof(ITweener)} on {nameof(InterpolationTweenBehaviour)} but it was already added"
);
}
_tweeners.Add(tweener);
_durationCalculated = false;
}
void StartTweeners()
{
_playingTweeners.Clear();
_playingTweeners.AddRange(_tweeners);
for (int i = _playingTweeners.Count - 1; i >= 0; --i)
{
ITweener tweener = _playingTweeners[i];
tweener.Start();
if (!tweener.IsPlaying)
{
_playingTweeners.RemoveAt(i);
}
}
if (_playingTweeners.Count == 0)
{
MarkFinished();
}
}
}
}

View file

@ -0,0 +1 @@
uid://cx1regaakoijq

View file

@ -0,0 +1,189 @@
using System.Collections.Generic;
using GTweens.Easings;
using GTweens.Enums;
using GTweens.Extensions;
using GTweens.Tweens;
namespace GTweens.TweenBehaviours
{
public sealed class SequenceTweenBehaviour : TweenBehaviour
{
public IReadOnlyList<GTween> Tweens => _tweens;
readonly List<GTween> _tweens = new();
readonly List<GTween> _playingTweens = new();
bool _durationCalculated;
float _cachedCalculatedDuration;
public override void Start(bool isCompletingInstantly)
{
StartTweens(isCompletingInstantly);
}
public override void Tick(float deltaTime)
{
if (_playingTweens.Count == 0)
{
MarkFinished();
return;
}
GTween gTween = _playingTweens[0];
gTween.Tick(deltaTime);
if (gTween.IsPlaying)
{
return;
}
_playingTweens.RemoveAt(0);
if (_playingTweens.Count > 0)
{
GTween nextGTween = _playingTweens[0];
nextGTween.Start();
}
else
{
Tick(deltaTime);
}
}
public override void Kill()
{
foreach (GTween tween in _playingTweens)
{
tween.Kill();
}
_playingTweens.Clear();
MarkFinished();
}
public override void Complete()
{
foreach (GTween tween in _tweens)
{
if(tween.IsCompleted)
{
continue;
}
if (!tween.IsPlaying)
{
tween.Start(isCompletingInstantly: true);
}
tween.Complete();
}
_playingTweens.Clear();
MarkFinished();
}
public override void Reset(bool kill, ResetMode resetMode)
{
for (int i = _tweens.Count - 1; i >= 0; --i)
{
GTween gTween = _tweens[i];
gTween.Reset(kill, resetMode);
}
MarkUnfinished();
}
public override void SetEasing(EasingDelegate easingFunction)
{
foreach (GTween tween in _tweens)
{
tween.SetEasing(easingFunction);
}
}
public override float GetDuration()
{
if(_durationCalculated)
{
return _cachedCalculatedDuration;
}
_durationCalculated = true;
_cachedCalculatedDuration = 0.0f;
foreach (GTween tween in _tweens)
{
_cachedCalculatedDuration += tween.GetDuration();
}
return _cachedCalculatedDuration;
}
public override float GetElapsed()
{
float totalDuration = 0.0f;
foreach (GTween tween in _tweens)
{
totalDuration += tween.GetElapsed();
}
return totalDuration;
}
public void Add(GTween gTween)
{
if (gTween.IsPlayingOrCompletedOrNested())
{
return;
}
gTween.IsNested = true;
_tweens.Add(gTween);
_durationCalculated = false;
}
public void Remove(GTween gTween)
{
if (gTween.IsPlayingOrCompleted())
{
return;
}
bool found = _tweens.Remove(gTween);
if (!found)
{
return;
}
gTween.IsNested = false;
_durationCalculated = false;
}
void StartTweens(bool isCompletingInstantly)
{
_playingTweens.Clear();
_playingTweens.AddRange(_tweens);
if (_playingTweens.Count > 0)
{
GTween gTween = _playingTweens[0];
gTween.Start(isCompletingInstantly);
}
else
{
MarkFinished();
}
}
}
}

View file

@ -0,0 +1 @@
uid://dm1lb1r6xblco

View file

@ -0,0 +1,34 @@
using System;
using GTweens.Easings;
using GTweens.Enums;
namespace GTweens.TweenBehaviours;
public abstract class TweenBehaviour : ITweenBehaviour
{
bool _finished;
public bool GetFinished() => _finished;
protected void MarkFinished() => _finished = true;
protected void MarkUnfinished() => _finished = false;
public float GetRemaining()
{
float duration = GetDuration();
float elapsed = GetElapsed();
return Math.Max(duration - elapsed, 0f);
}
public abstract float GetDuration();
public abstract float GetElapsed();
public virtual bool GetLoopable() => true;
public virtual void Start(bool isCompletingInstantly) { }
public virtual void Tick(float deltaTime) { }
public virtual void Kill() { }
public virtual void Complete() { }
public virtual void Reset(bool kill, ResetMode loopResetMode) { }
public virtual void SetEasing(EasingDelegate easingFunction) { }
}

View file

@ -0,0 +1 @@
uid://rx0cbwgbajym

View file

@ -0,0 +1,53 @@
using GTweens.Enums;
namespace GTweens.TweenBehaviours
{
public sealed class WaitTimeTweenBehaviour : TweenBehaviour
{
readonly float _durationSeconds;
float _elapsedSeconds;
public WaitTimeTweenBehaviour(float durationSeconds)
{
_durationSeconds = durationSeconds;
}
public override void Start(bool isCompletingInstantly)
{
_elapsedSeconds = 0f;
}
public override void Tick(float deltaTime)
{
_elapsedSeconds += deltaTime;
if (_elapsedSeconds >= _durationSeconds)
{
MarkFinished();
}
}
public override void Complete()
{
_elapsedSeconds = _durationSeconds;
MarkFinished();
}
public override void Reset(bool kill, ResetMode loopResetMode)
{
_elapsedSeconds = 0f;
MarkUnfinished();
}
public override float GetDuration()
{
return _durationSeconds;
}
public override float GetElapsed()
{
return _elapsedSeconds;
}
}
}

View file

@ -0,0 +1 @@
uid://m7stdrq84q6r

View file

@ -0,0 +1,25 @@
using GTweens.Delegates;
using GTweens.Interpolators;
namespace GTweens.Tweeners;
public sealed class FloatTweener : Tweener<float>
{
public FloatTweener(
Getter currentValueGetter,
Setter setter,
Getter to,
float duration,
ValidationDelegates.Validation validation
)
: base(
currentValueGetter,
setter,
to,
duration,
FloatInterpolator.Instance,
validation
)
{
}
}

View file

@ -0,0 +1 @@
uid://bywdapy07yjny

View file

@ -0,0 +1,25 @@
using GTweens.Easings;
using GTweens.Enums;
namespace GTweens.Tweeners
{
public interface ITweener
{
float Duration { get; }
float Elapsed { get; }
float Remaining { get; }
bool IsPlaying { get; }
bool IsCompleted { get; }
bool IsKilled { get; }
bool IsCompletedOrKilled { get; }
void SetEasing(EasingDelegate easingFunction);
void Reset(ResetMode mode);
void Start();
void Tick(float deltaTime);
void Complete();
void Kill();
}
}

View file

@ -0,0 +1 @@
uid://k17rtk6wh5xf

View file

@ -0,0 +1,26 @@
using GTweens.Delegates;
using GTweens.Interpolators;
namespace GTweens.Tweeners
{
public sealed class IntTweener : Tweener<int>
{
internal IntTweener(
Getter currValueGetter,
Setter setter,
Getter to,
float duration,
ValidationDelegates.Validation validation
)
: base(
currValueGetter,
setter,
to,
duration,
IntInterpolator.Instance,
validation
)
{
}
}
}

View file

@ -0,0 +1 @@
uid://ntjjh7jiu8vt

View file

@ -0,0 +1,26 @@
using System.Drawing;
using GTweens.Delegates;
using GTweens.Interpolators;
namespace GTweens.Tweeners
{
public sealed class SystemColorTweener : Tweener<Color>
{
public SystemColorTweener(
Getter currValueGetter,
Setter setter,
Getter to,
float duration,
ValidationDelegates.Validation validation
)
: base(currValueGetter,
setter,
to,
duration,
SystemColorInterpolator.Instance,
validation
)
{
}
}
}

View file

@ -0,0 +1 @@
uid://bugpyjerorwcw

View file

@ -0,0 +1,27 @@
using System.Numerics;
using GTweens.Delegates;
using GTweens.Interpolators;
namespace GTweens.Tweeners
{
public sealed class SystemQuaternionTweener : Tweener<Quaternion>
{
public SystemQuaternionTweener(
Getter currValueGetter,
Setter setter,
Getter to,
float duration,
ValidationDelegates.Validation validation
)
: base(
currValueGetter,
setter,
to,
duration,
SystemQuaternionInterpolator.Instance,
validation
)
{
}
}
}

View file

@ -0,0 +1 @@
uid://cvhxhs2yx2njy

View file

@ -0,0 +1,27 @@
using System.Numerics;
using GTweens.Delegates;
using GTweens.Interpolators;
namespace GTweens.Tweeners
{
public sealed class SystemVector2Tweener : Tweener<Vector2>
{
public SystemVector2Tweener(
Getter currValueGetter,
Setter setter,
Getter to,
float duration,
ValidationDelegates.Validation validation
)
: base(
currValueGetter,
setter,
to,
duration,
SystemVector2Interpolator.Instance,
validation
)
{
}
}
}

View file

@ -0,0 +1 @@
uid://ckm388yjwcuu6

View file

@ -0,0 +1,27 @@
using System.Numerics;
using GTweens.Delegates;
using GTweens.Interpolators;
namespace GTweens.Tweeners
{
public sealed class SystemVector3Tweener : Tweener<Vector3>
{
public SystemVector3Tweener(
Getter currValueGetter,
Setter setter,
Getter to,
float duration,
ValidationDelegates.Validation validation
)
: base(
currValueGetter,
setter,
to,
duration,
SystemVector3Interpolator.Instance,
validation
)
{
}
}
}

View file

@ -0,0 +1 @@
uid://bpptxf58855kt

View file

@ -0,0 +1,27 @@
using System.Numerics;
using GTweens.Delegates;
using GTweens.Interpolators;
namespace GTweens.Tweeners
{
public sealed class SystemVector4Tweener : Tweener<Vector4>
{
public SystemVector4Tweener(
Getter currValueGetter,
Setter setter,
Getter to,
float duration,
ValidationDelegates.Validation validation
)
: base(
currValueGetter,
setter,
to,
duration,
SystemVector4Interpolator.Instance,
validation
)
{
}
}
}

View file

@ -0,0 +1 @@
uid://b4534l80h30dx

View file

@ -0,0 +1,234 @@
using System;
using GTweens.Delegates;
using GTweens.Easings;
using GTweens.Enums;
using GTweens.Extensions;
using GTweens.Interpolators;
namespace GTweens.Tweeners
{
public abstract class Tweener<T> : ITweener
{
public delegate void Setter(T currentValue);
public delegate T Getter();
public bool IsPlaying { get; private set; }
public bool IsCompleted { get; private set; }
public bool IsKilled { get; private set; }
public bool IsCompletedOrKilled => IsCompleted || IsKilled;
public float Duration { get; }
public float Elapsed { get; private set; }
public float Remaining => Math.Max(Duration - Elapsed, 0f);
readonly Getter _getter;
readonly Setter _setter;
readonly Getter _to;
readonly ValidationDelegates.Validation _validation;
readonly IInterpolator<T> _interpolator;
bool _hasFirstTimeValues;
T _firstTimeInitialValue = default!;
T _firstTimeFinalValue = default!;
T _initialValue = default!;
T _finalValue = default!;
T _currentValue = default!;
EasingDelegate _easingFunction = PresetEasingDelegateFactory.GetEaseDelegate(Easing.Linear);
public Tweener(
Getter getter,
Setter setter,
Getter to,
float duration,
IInterpolator<T> interpolator,
ValidationDelegates.Validation validation
)
{
_getter = getter;
_setter = setter;
_to = to;
_interpolator = interpolator;
_validation = validation;
Duration = Math.Max(duration, 0.0f);
}
public void Start()
{
if (IsPlaying)
{
return;
}
IsPlaying = true;
IsCompleted = false;
IsKilled = false;
Elapsed = 0.0f;
bool valid = Validate();
if(!valid)
{
Kill();
return;
}
_initialValue = _getter.Invoke();
GetFirstTimeValues();
CompleteIfInstant();
}
public void Reset(ResetMode mode)
{
bool valid = Validate();
if (!valid)
{
Kill();
return;
}
GetFirstTimeValues();
IsCompleted = false;
IsKilled = false;
Elapsed = 0.0f;
switch (mode)
{
default:
case ResetMode.InitialValues:
{
_setter(_firstTimeInitialValue);
_finalValue = _firstTimeFinalValue;
}
break;
case ResetMode.IncrementalValues:
{
T difference = _interpolator.Subtract(_firstTimeInitialValue, _firstTimeFinalValue);
_finalValue = _interpolator.Add(_currentValue, difference);
}
break;
case ResetMode.PingPong:
{
_finalValue = _initialValue;
}
break;
}
}
public void Tick(float deltaTime)
{
if (!IsPlaying)
{
return;
}
bool valid = Validate();
if (!valid)
{
Kill();
return;
}
Elapsed = Math.Min(Duration, Elapsed + deltaTime);
if (Elapsed < Duration)
{
float timeNormalized = MathExtensions.SafeDivide(Elapsed, Duration);
_currentValue = _interpolator.Evaluate(
_initialValue,
_finalValue,
timeNormalized,
_easingFunction
);
_setter(_currentValue);
}
else
{
Complete();
}
}
public void Complete()
{
bool valid = Validate();
if (!valid)
{
return;
}
GetFirstTimeValues();
T newValue = _interpolator.Evaluate(
_initialValue,
_finalValue,
1.0f,
_easingFunction
);
_setter(newValue);
IsPlaying = false;
IsCompleted = true;
}
public void Kill()
{
IsKilled = true;
IsPlaying = false;
}
public void SetEasing(EasingDelegate easingFunction)
{
_easingFunction = easingFunction;
}
void CompleteIfInstant()
{
if (!IsPlaying)
{
return;
}
bool isInstant = Duration == 0.0f;
if (isInstant)
{
Complete();
}
}
bool Validate()
{
return _validation.Invoke();
}
void GetFirstTimeValues()
{
if (_hasFirstTimeValues)
{
return;
}
_hasFirstTimeValues = true;
_finalValue = _to.Invoke();
_firstTimeInitialValue = _initialValue;
_firstTimeFinalValue = _finalValue;
}
}
}

View file

@ -0,0 +1 @@
uid://cy5dli5pvpgrj

View file

@ -0,0 +1,27 @@
// using Juce.Tweening.Interpolators;
// using UnityEngine;
//
// namespace Juce.Tweening.Tweeners
// {
// public class Vector3RotationTweener : Tweener<Vector3>
// {
// public Vector3RotationTweener(
// Getter currValueGetter,
// Setter setter,
// Getter finalValueGetter,
// RotationMode rotationMode,
// float duration,
// Validation validation
// )
// : base(
// currValueGetter,
// setter,
// finalValueGetter,
// duration,
// new SystemVector3RotationInterpolator(rotationMode),
// validation
// )
// {
// }
// }
// }

View file

@ -0,0 +1 @@
uid://by4baldnaurb8

View file

@ -0,0 +1,423 @@
using System;
using GTweens.Easings;
using GTweens.Enums;
using GTweens.TweenBehaviours;
namespace GTweens.Tweens
{
/// <summary>
/// Represents the core item for building tweening animations.
/// </summary>
public sealed class GTween
{
public event Action? OnStartAction;
public event Action? OnTickAction;
public event Action? OnLoopAction;
public event Action? OnResetAction;
public event Action? OnCompleteAction;
public event Action? OnKillAction;
public event Action? OnCompleteOrKillAction;
public event Action<float>? OnTimeScaleChangedAction;
public ITweenBehaviour Behaviour { get; }
public float TimeScale { get; private set; } = 1;
public float Delay { get; private set; }
public int Loops { get; private set; }
public ResetMode LoopResetMode { get; private set; }
public bool IsNested { get; set; }
public bool IsPlaying { get; private set; }
public bool IsPaused { get; private set; }
public bool IsCompleted { get; private set; }
public bool IsKilled { get; private set; }
public bool IsCompletedOrKilled => IsCompleted || IsKilled;
public bool IsAlive { get; set; }
float _delayRemaining;
int _loopsRemaining;
public GTween(ITweenBehaviour behaviour)
{
Behaviour = behaviour;
}
/// <summary>
/// Starts the tween.
/// </summary>
/// <param name="isCompletingInstantly">Determines if the tween should complete instantly.</param>
public void Start(bool isCompletingInstantly = false)
{
if (IsPlaying)
{
Kill();
}
IsPlaying = true;
IsCompleted = false;
IsKilled = false;
_delayRemaining = Delay;
_loopsRemaining = Loops;
Behaviour.Start(isCompletingInstantly);
OnStartAction?.Invoke();
}
/// <summary>
/// Advances the tween by a given delta time.
/// </summary>
/// <param name="deltaTime">The elapsed time since the last update.</param>
public void Tick(float deltaTime)
{
if (!IsPlaying)
{
return;
}
if (IsPaused)
{
return;
}
float deltaTimeWithTimeScale = TimeScale * deltaTime;
if (_delayRemaining > 0f)
{
_delayRemaining -= deltaTime;
return;
}
Behaviour.Tick(deltaTimeWithTimeScale);
OnTickAction?.Invoke();
bool isFinished = Behaviour.GetFinished();
if (!isFinished)
{
return;
}
bool needsToLoop = _loopsRemaining > 0 && Behaviour.GetLoopable();
if(needsToLoop)
{
Loop(LoopResetMode);
}
else
{
MarkFinished();
}
}
/// <summary>
/// Sets if the tween can continue updating or not. Has effect even if the tween has not startet playing.
/// If you start a paused tween, it will not update until it's unpaused.
/// </summary>
public GTween SetPaused(bool paused)
{
IsPaused = paused;
return this;
}
/// <summary>
/// Instantly reaches the final state of the tween, and stops playing.
/// </summary>
public void Complete()
{
if (!IsPlaying && !IsCompleted)
{
Start(true);
}
Behaviour.Complete();
_loopsRemaining = 0;
MarkFinished();
}
/// <summary>
/// Kills the tween. This means that the tween will stop playing, leaving it at its current state.
/// </summary>
public void Kill()
{
if (!IsPlaying)
{
return;
}
IsPlaying = false;
IsCompleted = false;
IsKilled = true;
Behaviour.Kill();
OnKillAction?.Invoke();
OnCompleteOrKillAction?.Invoke();
}
/// <summary>
/// Resets the tween, optionally killing it and specifying the reset mode.
/// </summary>
/// <param name="kill">Whether to kill the tween.</param>
/// <param name="resetMode">The reset mode to use.</param>
/// <returns>The current GTween instance for method chaining.</returns>
public GTween Reset(bool kill, ResetMode resetMode = ResetMode.InitialValues)
{
if (kill)
{
Kill();
IsPlaying = false;
}
IsCompleted = false;
IsKilled = false;
_delayRemaining = Delay;
Behaviour.Reset(kill, resetMode);
OnResetAction?.Invoke();
return this;
}
/// <summary>
/// Simulates the progress of a GTween animation for a specified duration.
/// </summary>
/// <param name="time">The simulated time in seconds.</param>
/// <returns>The current GTween instance for method chaining.</returns>
public GTween Simulate(float time)
{
if (!IsPlaying)
{
Start();
}
bool loops = Loops > 0;
float simulationTime = loops ?
time % Behaviour.GetDuration() :
Math.Min(time, Behaviour.GetDuration());
float progress = Behaviour.GetElapsed();
while (simulationTime > 0)
{
Tick(simulationTime);
float newProgress = Behaviour.GetElapsed();
float tickElapsed = newProgress - progress;
progress = newProgress;
simulationTime -= tickElapsed;
}
return this;
}
/// <summary>
/// Adds some delay (in seconds) at the begining of the tween.
/// </summary>
public GTween SetDelay(float delaySeconds)
{
Delay = delaySeconds;
return this;
}
/// <summary>
/// Sets the time scale for the tween, affecting its speed.
/// By default time scale is 1.0f. If you decrease this number, the tween
/// will update slower. If you increase it, the tween will update faster.
/// </summary>
/// <param name="timeScale">The time scale to set.</param>
/// <returns>The current GTween instance for method chaining.</returns>
public GTween SetTimeScale(float timeScale)
{
TimeScale = timeScale;
OnTimeScaleChangedAction?.Invoke(timeScale);
return this;
}
/// <summary>
/// Sets the easing function for the tween.
/// </summary>
/// <param name="easingFunction">The custom easing function to use.</param>
/// <returns>The current GTween instance for method chaining.</returns>
public GTween SetEasing(EasingDelegate easingFunction)
{
Behaviour.SetEasing(easingFunction);
return this;
}
/// <summary>
/// Sets the predefined easing function for the tween.
/// </summary>
/// <param name="easing">The predefined easing to use.</param>
/// <returns>The current GTween instance for method chaining.</returns>
public GTween SetEasing(Easing easing)
{
return SetEasing(PresetEasingDelegateFactory.GetEaseDelegate(easing));
}
/// <summary>
/// Sets the number of loops and the reset mode for the tween.
/// </summary>
/// <param name="loops">The number of loops.</param>
/// <param name="resetMode">The reset mode to use when looping.</param>
/// <returns>The current GTween instance for method chaining.</returns>
public GTween SetLoops(int loops, ResetMode resetMode = ResetMode.InitialValues)
{
Loops = Math.Max(loops, 0);
LoopResetMode = resetMode;
return this;
}
/// <summary>
/// Sets the tween to have and almost infinite amount of loops with the specified reset mode.
/// </summary>
/// <param name="resetMode">The reset mode to use when looping.</param>
/// <returns>The current GTween instance for method chaining.</returns>
public GTween SetMaxLoops(ResetMode resetMode = ResetMode.InitialValues)
{
return SetLoops(int.MaxValue, resetMode);
}
/// <summary>
/// Calculates the total duration of the tween.
/// </summary>
public float GetDuration()
{
return Behaviour.GetDuration();
}
/// <summary>
/// Calculates the time elapsed since the tween started playing.
/// </summary>
public float GetElapsed()
{
if(!IsPlaying && !IsCompleted)
{
return 0f;
}
if(!IsPlaying && IsCompleted)
{
return GetDuration();
}
return Behaviour.GetElapsed();
}
/// <summary>
/// Gets the time left remaining on the tween (duration - elapsed).
/// </summary>
public float GetRemaining()
{
if(!IsPlaying && !IsCompleted)
{
return GetDuration();
}
if(!IsPlaying && IsCompleted)
{
return 0f;
}
return Behaviour.GetRemaining();
}
public GTween OnStart(Action action)
{
OnStartAction += action;
return this;
}
public GTween OnTick(Action action)
{
OnTickAction += action;
return this;
}
public GTween OnLoop(Action action)
{
OnLoopAction += action;
return this;
}
public GTween OnReset(Action action)
{
OnResetAction += action;
return this;
}
public GTween OnComplete(Action action)
{
OnCompleteAction += action;
return this;
}
public GTween OnKill(Action action)
{
OnKillAction += action;
return this;
}
public GTween OnCompleteOrKill(Action action)
{
OnCompleteOrKillAction += action;
return this;
}
public GTween OnTimeScaleChanged(Action<float> action)
{
OnTimeScaleChangedAction += action;
return this;
}
void Loop(ResetMode loopResetMode)
{
bool needsToLoop = _loopsRemaining > 0;
if(!needsToLoop || !Behaviour.GetLoopable())
{
return;
}
--_loopsRemaining;
Reset(kill: false, loopResetMode);
IsPlaying = true;
IsCompleted = false;
IsKilled = false;
Behaviour.Start(false);
OnLoopAction?.Invoke();
}
void MarkFinished()
{
if (!IsPlaying)
{
return;
}
IsPlaying = false;
IsCompleted = true;
IsKilled = false;
Behaviour.Complete();
OnCompleteAction?.Invoke();
OnCompleteOrKillAction?.Invoke();
}
}
}

View file

@ -0,0 +1 @@
uid://d2cnyj34v2qq4