96 lines
3.7 KiB
C#
96 lines
3.7 KiB
C#
using System;
|
|
|
|
namespace Cryville.Common {
|
|
public class PropertyTweener<T> {
|
|
readonly Func<T> _getter;
|
|
readonly Action<T> _setter;
|
|
readonly Tweener<T> _tweener;
|
|
public PropertyTweener(Func<T> getter, Action<T> setter, Tweener<T> tweener) {
|
|
_getter = getter;
|
|
_setter = setter;
|
|
_tweener = tweener;
|
|
var initialValue = getter();
|
|
_tweener.Start(initialValue, initialValue, float.Epsilon);
|
|
}
|
|
public PropertyTweener<T> Start(T endValue, float duration) {
|
|
_tweener.Start(_getter(), endValue, duration);
|
|
return this;
|
|
}
|
|
public void Advance(float deltaTime) {
|
|
if (!_tweener.Advance(deltaTime, out var value)) return;
|
|
_setter(value);
|
|
}
|
|
}
|
|
public delegate T Addition<T>(T a, T b);
|
|
public delegate T Multiplication<T>(float k, T b);
|
|
public delegate float EasingFunction(float t);
|
|
public class Tweener<T> {
|
|
readonly Addition<T> _addition;
|
|
readonly Multiplication<T> _multiplication;
|
|
public Tweener(Addition<T> addition, Multiplication<T> multiplication) {
|
|
_addition = addition;
|
|
_multiplication = multiplication;
|
|
}
|
|
public EasingFunction EasingFunction { get; set; } = EasingFunctions.Linear;
|
|
public Tweener<T> With(EasingFunction easing) {
|
|
EasingFunction = easing;
|
|
return this;
|
|
}
|
|
|
|
T _startValue = default;
|
|
T _endValue = default;
|
|
float _duration = float.Epsilon;
|
|
float _time;
|
|
bool _endOfTween;
|
|
public Tweener<T> Start(T startValue, T endValue, float duration) {
|
|
_startValue = startValue;
|
|
_endValue = endValue;
|
|
_duration = duration;
|
|
_time = 0;
|
|
_endOfTween = false;
|
|
return this;
|
|
}
|
|
public bool Advance(float deltaTime, out T value) {
|
|
if (_endOfTween) {
|
|
value = _endValue;
|
|
return false;
|
|
}
|
|
if (_time >= _duration) {
|
|
value = _endValue;
|
|
_endOfTween = true;
|
|
return true;
|
|
}
|
|
_time += deltaTime;
|
|
var ratio = EasingFunction(System.Math.Clamp(_time / _duration, 0, 1));
|
|
value = _addition(_multiplication(1 - ratio, _startValue), _multiplication(ratio, _endValue));
|
|
return true;
|
|
}
|
|
public Tweener<object> Boxed() {
|
|
return new Tweener<object>((a, b) => _addition((T)a, (T)b), (k, v) => _multiplication(k, (T)v));
|
|
}
|
|
}
|
|
public static class Tweeners {
|
|
public static Tweener<byte> Byte => new((a, b) => (byte)(a + b), (k, v) => (byte)(k * v));
|
|
public static Tweener<sbyte> SByte => new((a, b) => (sbyte)(a + b), (k, v) => (sbyte)(k * v));
|
|
public static Tweener<short> Int16 => new((a, b) => (short)(a + b), (k, v) => (short)(k * v));
|
|
public static Tweener<ushort> UInt16 => new((a, b) => (ushort)(a + b), (k, v) => (ushort)(k * v));
|
|
public static Tweener<int> Int32 => new((a, b) => a + b, (k, v) => (int)(k * v));
|
|
public static Tweener<uint> UInt32 => new((a, b) => a + b, (k, v) => (uint)(k * v));
|
|
public static Tweener<long> Int64 => new((a, b) => a + b, (k, v) => (long)(k * v));
|
|
public static Tweener<ulong> UInt64 => new((a, b) => a + b, (k, v) => (ulong)(k * v));
|
|
public static Tweener<IntPtr> IntPtr => new((a, b) => new IntPtr((long)a + (long)b), (k, v) => new IntPtr((long)(k * (long)v)));
|
|
public static Tweener<UIntPtr> UIntPtr => new((a, b) => new UIntPtr((ulong)a + (ulong)b), (k, v) => new UIntPtr((ulong)(k * (ulong)v)));
|
|
public static Tweener<float> Float => new((a, b) => a + b, (k, v) => k * v);
|
|
public static Tweener<double> Double => new((a, b) => a + b, (k, v) => k * v);
|
|
}
|
|
public static class EasingFunctions {
|
|
public static float Linear(float x) => x;
|
|
public static float InQuad(float x) => x * x;
|
|
public static float InCubic(float x) => x * x * x;
|
|
public static float InSine(float x) => 1 - OutSine(1 - x);
|
|
public static float OutQuad(float x) => 1 - InQuad(1 - x);
|
|
public static float OutCubic(float x) => 1 - InCubic(1 - x);
|
|
public static float OutSine(float x) => MathF.Sin(x * MathF.PI / 2);
|
|
}
|
|
}
|