diff --git a/LemonUI/TinyTween/FloatTween.cs b/LemonUI/TinyTween/FloatTween.cs new file mode 100644 index 0000000..4d0d0ce --- /dev/null +++ b/LemonUI/TinyTween/FloatTween.cs @@ -0,0 +1,23 @@ +namespace LemonUI.TinyTween +{ + /// + /// Represents a tween for floating-point values. + /// + public class FloatTween : Tween + { + private static readonly LerpFunc LerpFunc = LerpFloat; + + private static float LerpFloat(float start, float end, float progress) + { + return start + ((end - start) * progress); + } + + /// + /// Initializes a new instance of the FloatTween class. + /// + public FloatTween() + : base(LerpFunc) + { + } + } +} diff --git a/LemonUI/TinyTween/ITween.cs b/LemonUI/TinyTween/ITween.cs new file mode 100644 index 0000000..f81df23 --- /dev/null +++ b/LemonUI/TinyTween/ITween.cs @@ -0,0 +1,52 @@ +namespace LemonUI.TinyTween +{ + /// + /// Represents an interface for a tween with different stop behaviors. + /// + public interface ITween + { + /// + /// Gets the current state of the tween. + /// + TweenState State { get; } + /// + /// Pauses the tween. + /// + void Pause(); + /// + /// Resumes the paused tween. + /// + void Resume(); + /// + /// Stops the tween with the specified stop behavior. + /// + /// The stop behavior of the tween. + void Stop(StopBehavior stopBehavior); + /// + /// Updates the tween with the elapsed time. + /// + /// The elapsed time since the last update. + void Update(float elapsedTime); + } + + /// + /// Represents an interface for a typed tween with different stop behaviors. + /// + /// The type of value being tweened. + public interface ITween : ITween + where T : struct + { + /// + /// Gets the current value of the tween. + /// + T CurrentValue { get; } + /// + /// Starts the tween with the specified start and end values, duration, and scale function. + /// + /// The starting value of the tween. + /// The ending value of the tween. + /// The duration of the tween. + /// The scale function to be used for the tween. + void Start(T start, T end, float duration, ScaleFunc scaleFunc); + } +} diff --git a/LemonUI/TinyTween/LerpFunc.cs b/LemonUI/TinyTween/LerpFunc.cs new file mode 100644 index 0000000..2dced37 --- /dev/null +++ b/LemonUI/TinyTween/LerpFunc.cs @@ -0,0 +1,12 @@ +namespace LemonUI.TinyTween +{ + /// + /// Represents a delegate for a lerp function used in a tween. + /// + /// The type of value being lerped. + /// The starting value of the lerp. + /// The ending value of the lerp. + /// The progress of the lerp. + /// The lerped value based on the progress. + public delegate T LerpFunc(T start, T end, float progress); +} diff --git a/LemonUI/TinyTween/ScaleFunc.cs b/LemonUI/TinyTween/ScaleFunc.cs new file mode 100644 index 0000000..7c2d89f --- /dev/null +++ b/LemonUI/TinyTween/ScaleFunc.cs @@ -0,0 +1,9 @@ +namespace LemonUI.TinyTween +{ + /// + /// Represents a delegate for a scale function used in a tween. + /// + /// The progress of the tween. + /// The scaled value based on the progress. + public delegate float ScaleFunc(float progress); +} diff --git a/LemonUI/TinyTween/ScaleFuncs.cs b/LemonUI/TinyTween/ScaleFuncs.cs new file mode 100644 index 0000000..6345313 --- /dev/null +++ b/LemonUI/TinyTween/ScaleFuncs.cs @@ -0,0 +1,279 @@ +using System; + +namespace LemonUI.TinyTween +{ + /// + /// Provides a collection of scale functions for use in tweens. + /// + public static class ScaleFuncs + { + #region Fields + /// + /// Represents a linear scale function. + /// + public static readonly ScaleFunc Linear = LinearImpl; + /// + /// Represents a quadratic ease-in scale function. + /// + public static readonly ScaleFunc QuadraticEaseIn = QuadraticEaseInImpl; + /// + /// Represents a quadratic ease-out scale function. + /// + public static readonly ScaleFunc QuadraticEaseOut = QuadraticEaseOutImpl; + /// + /// Represents a quadratic ease-in-out scale function. + /// + public static readonly ScaleFunc QuadraticEaseInOut = QuadraticEaseInOutImpl; + /// + /// Represents a cubic ease-in scale function. + /// + public static readonly ScaleFunc CubicEaseIn = CubicEaseInImpl; + /// + /// Represents a cubic ease-out scale function. + /// + public static readonly ScaleFunc CubicEaseOut = CubicEaseOutImpl; + /// + /// Represents a cubic ease-in-out scale function. + /// + public static readonly ScaleFunc CubicEaseInOut = CubicEaseInOutImpl; + /// + /// Represents a quartic ease-in scale function. + /// + public static readonly ScaleFunc QuarticEaseIn = QuarticEaseInImpl; + /// + /// Represents a quartic ease-out scale function. + /// + public static readonly ScaleFunc QuarticEaseOut = QuarticEaseOutImpl; + /// + /// Represents a quartic ease-in-out scale function. + /// + public static readonly ScaleFunc QuarticEaseInOut = QuarticEaseInOutImpl; + /// + /// Represents a quintic ease-in scale function. + /// + public static readonly ScaleFunc QuinticEaseIn = QuinticEaseInImpl; + /// + /// Represents a quintic ease-out scale function. + /// + public static readonly ScaleFunc QuinticEaseOut = QuinticEaseOutImpl; + /// + /// Represents a quintic ease-in-out scale function. + /// + public static readonly ScaleFunc QuinticEaseInOut = QuinticEaseInOutImpl; + /// + /// Represents a sine ease-in scale function. + /// + public static readonly ScaleFunc SineEaseIn = SineEaseInImpl; + /// + /// Represents a sine ease-out scale function. + /// + public static readonly ScaleFunc SineEaseOut = SineEaseOutImpl; + /// + /// Represents a sine ease-in-out scale function. + /// + public static readonly ScaleFunc SineEaseInOut = SineEaseInOutImpl; + #endregion + + #region Functions + /// + /// Returns the progress as is, resulting in a linear scale. + /// + /// The progress value between 0 and 1. + /// The linear scale value. + public static float LinearImpl(float progress) + { + return progress; + } + + /// + /// Applies quadratic ease-in to the progress. + /// + /// The progress value between 0 and 1. + /// The eased-in scale value. + public static float QuadraticEaseInImpl(float progress) + { + return EaseInPower(progress, 2); + } + + /// + /// Applies quadratic ease-out to the progress. + /// + /// The progress value between 0 and 1. + /// The eased-out scale value. + public static float QuadraticEaseOutImpl(float progress) + { + return EaseOutPower(progress, 2); + } + + /// + /// Applies quadratic ease-in-out to the progress. + /// + /// The progress value between 0 and 1. + /// The eased-in-out scale value. + public static float QuadraticEaseInOutImpl(float progress) + { + return EaseInOutPower(progress, 2); + } + + /// + /// Applies cubic ease-in to the progress. + /// + /// The progress value between 0 and 1. + /// The eased-in scale value. + public static float CubicEaseInImpl(float progress) + { + return EaseInPower(progress, 3); + } + + /// + /// Applies cubic ease-out to the progress. + /// + /// The progress value between 0 and 1. + /// The eased-out scale value. + public static float CubicEaseOutImpl(float progress) + { + return EaseOutPower(progress, 3); + } + + /// + /// Applies cubic ease-in-out to the progress. + /// + /// The progress value between 0 and 1. + /// The eased-in-out scale value. + public static float CubicEaseInOutImpl(float progress) + { + return EaseInOutPower(progress, 3); + } + + /// + /// Applies quartic ease-in to the progress. + /// + /// The progress value between 0 and 1. + /// Returns the progress value modified with quadratic ease-in. + public static float QuarticEaseInImpl(float progress) + { + return EaseInPower(progress, 4); + } + + /// + /// Applies quartic ease-out to the progress. + /// + /// The progress value between 0 and 1. + /// Returns the progress value modified with quadratic ease-out. + public static float QuarticEaseOutImpl(float progress) + { + return EaseOutPower(progress, 4); + } + + /// + /// Applies quartic ease-in-out to the progress. + /// + /// The progress value between 0 and 1. + /// Returns the progress value modified with quadratic ease-in-out. + public static float QuarticEaseInOutImpl(float progress) + { + return EaseInOutPower(progress, 4); + } + + /// + /// Applies quintic ease-in to the progress. + /// + /// The progress value between 0 and 1. + /// Returns the progress value modified with quintic ease-in. + public static float QuinticEaseInImpl(float progress) + { + return EaseInPower(progress, 5); + } + + /// + /// Applies quintic ease-out to the progress. + /// + /// The progress value between 0 and 1. + /// Returns the progress value modified with quintic ease-out. + public static float QuinticEaseOutImpl(float progress) + { + return EaseOutPower(progress, 5); + } + + /// + /// Applies quintic ease-in-out to the progress. + /// + /// The progress value between 0 and 1. + /// Returns the progress value modified with quintic ease-in-out. + public static float QuinticEaseInOutImpl(float progress) + { + return EaseInOutPower(progress, 5); + } + + /// + /// Applies ease-in power to the progress with the specified power. + /// + /// The progress value between 0 and 1. + /// The power value for the ease-out function. + /// The modified progress value with ease-in power. + public static float EaseInPower(float progress, int power) + { + return (float)Math.Pow(progress, power); + } + + /// + /// Applies ease-out power to the progress with the specified power. + /// + /// The progress value between 0 and 1. + /// The power value for the ease-out function. + /// The modified progress value with ease-out power. + public static float EaseOutPower(float progress, int power) + { + int sign = (power % 2 != 0) ? 1 : -1; + return (float)(sign * (Math.Pow(progress - 1f, power) + sign)); + } + + /// + /// Applies ease-in-out power to the progress with the specified power. + /// + /// The progress value between 0 and 1. + /// The power value for the ease-out function. + /// The modified progress value with ease-in-out power. + public static float EaseInOutPower(float progress, int power) + { + progress *= 2f; + if (progress < 1f) + { + return (float)Math.Pow(progress, power) / 2f; + } + int sign = (power % 2 != 0) ? 1 : -1; + return (float)(sign / 2.0 * (Math.Pow(progress - 2f, power) + (sign * 2))); + } + + /// + /// Applies sine ease-in to the progress. + /// + /// The progress value between 0 and 1. + /// The modified progress value with sine ease-in. + public static float SineEaseInImpl(float progress) + { + return (float)Math.Sin((progress * (float)Math.PI / 2f) - ((float)Math.PI / 2f)) + 1f; + } + + /// + /// Applies sine ease-out to the progress. + /// + /// The progress value between 0 and 1. + /// The modified progress value with sine ease-out. + public static float SineEaseOutImpl(float progress) + { + return (float)Math.Sin(progress * (float)Math.PI / 2f); + } + + /// + /// Applies sine ease-in-out to the progress. + /// + /// The progress value between 0 and 1. + /// The modified progress value with sine ease-in-out. + public static float SineEaseInOutImpl(float progress) + { + return (float)(Math.Sin((progress * (float)Math.PI) - ((float)Math.PI / 2f)) + 1.0) / 2f; + } + #endregion + } +} diff --git a/LemonUI/TinyTween/StopBehavior.cs b/LemonUI/TinyTween/StopBehavior.cs new file mode 100644 index 0000000..222181a --- /dev/null +++ b/LemonUI/TinyTween/StopBehavior.cs @@ -0,0 +1,17 @@ +namespace LemonUI.TinyTween +{ + /// + /// Enumeration representing different stop behaviors of a tween. + /// + public enum StopBehavior + { + /// + /// Represents the "as is" stop behavior of a tween. + /// + AsIs, + /// + /// Represents the "force complete" stop behavior of a tween. + /// + ForceComplete + } +} diff --git a/LemonUI/TinyTween/Tween.cs b/LemonUI/TinyTween/Tween.cs new file mode 100644 index 0000000..02fe76c --- /dev/null +++ b/LemonUI/TinyTween/Tween.cs @@ -0,0 +1,172 @@ +using System; + +namespace LemonUI.TinyTween +{ + /// + /// Represents a generic tween with different stop behaviors. + /// + /// The type of value being tweened. + public class Tween : ITween, ITween + where T : struct + { + #region Fields + /// + /// The lerp function used for the tween. + /// + private readonly LerpFunc lerpFunc; + /// + /// The current time of the tween. + /// + private float currentTime; + /// + /// The duration of the tween. + /// + private float duration; + /// + /// The scale function used for the tween. + /// + private ScaleFunc scaleFunc; + /// + /// The state of the tween. + /// + private TweenState state; + /// + /// The starting value of the tween. + /// + private T start; + /// + /// The ending value of the tween. + /// + private T end; + /// + /// The current value of the tween. + /// + private T value; + /// + /// Gets the current time of the tween. + /// + public float CurrentTime => currentTime; + /// + /// Gets the duration of the tween. + /// + public float Duration => duration; + /// + /// Gets the state of the tween. + /// + public TweenState State => state; + /// + /// Gets the starting value of the tween. + /// + public T StartValue => start; + /// + /// Gets the ending value of the tween. + /// + public T EndValue => end; + /// + /// Gets the current value of the tween. + /// + public T CurrentValue => value; + #endregion + + #region Constructors + /// + /// Initializes a new instance of the Tween class with the specified lerp function. + /// + /// The lerp function used for the tween. + public Tween(LerpFunc lerpFunc) + { + this.lerpFunc = lerpFunc; + state = TweenState.Stopped; + } + #endregion + + #region Functions + /// + /// Starts the tween with the specified start and end values, duration, and scale function. + /// + /// The starting value of the tween. + /// The ending value of the tween. + /// The duration of the tween. + /// The scale function to be used for the tween. + /// Thrown when the duration is less than or equal to 0. + /// Thrown when the scaleFunc is null. + public void Start(T start, T end, float duration, ScaleFunc scaleFunc) + { + if (duration <= 0f) + { + throw new ArgumentException("duration must be greater than 0"); + } + if (scaleFunc == null) + { + throw new ArgumentNullException("scaleFunc"); + } + currentTime = 0f; + this.duration = duration; + this.scaleFunc = scaleFunc; + state = TweenState.Running; + this.start = start; + this.end = end; + UpdateValue(); + } + + /// + /// Pauses the tween if it is currently running. + /// + public void Pause() + { + if (state == TweenState.Running) + { + state = TweenState.Paused; + } + } + + /// + /// Resumes the tween if it is currently paused. + /// + public void Resume() + { + if (state == TweenState.Paused) + { + state = TweenState.Running; + } + } + + /// + /// Stops the tween with the specified stop behavior. + /// + /// The stop behavior to apply. + public void Stop(StopBehavior stopBehavior) + { + state = TweenState.Stopped; + if (stopBehavior == StopBehavior.ForceComplete) + { + currentTime = duration; + UpdateValue(); + } + } + + /// + /// Updates the tween with the specified elapsed time. + /// + /// The elapsed time since the last update. + public void Update(float elapsedTime) + { + if (state == TweenState.Running) + { + currentTime += elapsedTime; + if (currentTime >= duration) + { + currentTime = duration; + state = TweenState.Stopped; + } + UpdateValue(); + } + } + + private void UpdateValue() + { + value = lerpFunc(start, end, scaleFunc(currentTime / duration)); + } + #endregion + } +} \ No newline at end of file diff --git a/LemonUI/TinyTween/TweenState.cs b/LemonUI/TinyTween/TweenState.cs new file mode 100644 index 0000000..48fa5ec --- /dev/null +++ b/LemonUI/TinyTween/TweenState.cs @@ -0,0 +1,21 @@ +namespace LemonUI.TinyTween +{ + /// + /// Enumeration representing different states of a tween. + /// + public enum TweenState + { + /// + /// Represents the running state of a tween. + /// + Running, + /// + /// Represents the paused state of a tween. + /// + Paused, + /// + /// Represents the stopped state of a tween. + /// + Stopped + } +}