From 9526fe42b929e578441f46700cbe60a4bd75bc69 Mon Sep 17 00:00:00 2001 From: Speiger Date: Wed, 5 Jun 2024 22:54:37 +0200 Subject: [PATCH] Added Easing functions for the gui Animations --- TESTS_TO_DO.md | 3 + .../src/coreengine/math/MathUtils.java | 1 + .../coreengine/math/misc/EasingFunctions.java | 58 +++++++++++++++++++ .../src/coreengine/math/misc/IEasing.java | 11 ++++ .../gui/animation/GuiAnimationSnapshot.java | 10 +++- .../rendering/gui/animation/GuiAnimator.java | 5 ++ .../rendering/gui/animation/IAction.java | 11 +++- .../gui/animation/actions/EasedAction.java | 27 +++++++++ 8 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 TESTS_TO_DO.md create mode 100644 src/main/java/speiger/src/coreengine/math/misc/EasingFunctions.java create mode 100644 src/main/java/speiger/src/coreengine/math/misc/IEasing.java create mode 100644 src/main/java/speiger/src/coreengine/rendering/gui/animation/actions/EasedAction.java diff --git a/TESTS_TO_DO.md b/TESTS_TO_DO.md new file mode 100644 index 0000000..15d3ce6 --- /dev/null +++ b/TESTS_TO_DO.md @@ -0,0 +1,3 @@ +# Tests that should be done. + +- Test starting animations with delays of each other to see if they act properly. \ No newline at end of file diff --git a/src/main/java/speiger/src/coreengine/math/MathUtils.java b/src/main/java/speiger/src/coreengine/math/MathUtils.java index c4e62a8..ca87f24 100644 --- a/src/main/java/speiger/src/coreengine/math/MathUtils.java +++ b/src/main/java/speiger/src/coreengine/math/MathUtils.java @@ -5,6 +5,7 @@ public class MathUtils { private static final float[] COS_TABLE; private static final float TABLE_MASK; private static final int SIN_MASK; + public static final double HALF_PI = Math.PI * 0.5D; public static final double PI_INVERSION = 180D / Math.PI; public static float sin(float a) { diff --git a/src/main/java/speiger/src/coreengine/math/misc/EasingFunctions.java b/src/main/java/speiger/src/coreengine/math/misc/EasingFunctions.java new file mode 100644 index 0000000..3ac5d8b --- /dev/null +++ b/src/main/java/speiger/src/coreengine/math/misc/EasingFunctions.java @@ -0,0 +1,58 @@ +package speiger.src.coreengine.math.misc; + +import speiger.src.coreengine.math.MathUtils; + +public class EasingFunctions { + public static double easeInSine(double progress) { + return 1D - MathUtils.cos(progress * MathUtils.HALF_PI); + } + + public static double easeOutSine(double progress) { + return MathUtils.sin(progress * MathUtils.HALF_PI); + } + + public static double easeInOutSine(double progress) { + return -MathUtils.cos(progress * Math.PI - 1D) * 0.5D; + } + + public static double easeInSqrt(double progress) { + return Math.sqrt(progress); + } + + public static double easeOutSqrt(double progress) { + return 1D - Math.sqrt(1D - progress); + } + + public static double easeInOutSqrt(double progress) { + return progress < 0.5D ? Math.sqrt(progress) : 1D-Math.sqrt(1-progress); + } + + public static double easeInQuad(double progress) { + return progress * progress; + } + + public static double easeOutQuad(double progress) { + double inverse = 1D - progress; + return 1D - (inverse * inverse); + } + + public static double easeInOutQuad(double progress) { + if(progress < 0.5D) return 2D * progress * progress; + double inverse = 1D - progress; + return 1D - (-4D * (1D - inverse * inverse) + 4D) * 0.5D; + } + + public static double easeInExpo(double progress) { + return Math.pow(2D, (10D * progress) - 10D); + } + + public static double easeOutExpo(double progress) { + return 1D - Math.pow(2D, -10D * progress); + } + + public static double easeInOutExpo(double progress) { + return progress <= 0.5D ? Math.pow(2D, (20D * progress) - 10D) * 0.5D : (2D - Math.pow(2D, (-20D * progress) + 10D)) * 0.5D; + } + + +} diff --git a/src/main/java/speiger/src/coreengine/math/misc/IEasing.java b/src/main/java/speiger/src/coreengine/math/misc/IEasing.java new file mode 100644 index 0000000..fa480d4 --- /dev/null +++ b/src/main/java/speiger/src/coreengine/math/misc/IEasing.java @@ -0,0 +1,11 @@ +package speiger.src.coreengine.math.misc; + +import speiger.src.coreengine.math.MathUtils; + +public interface IEasing { + public double ease(double progress); + + public default double ease(double progress, double max) { + return ease(MathUtils.clamp(progress/max, 0D, 1D)); + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/animation/GuiAnimationSnapshot.java b/src/main/java/speiger/src/coreengine/rendering/gui/animation/GuiAnimationSnapshot.java index bfe487a..0c396d1 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/animation/GuiAnimationSnapshot.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/animation/GuiAnimationSnapshot.java @@ -15,6 +15,7 @@ public class GuiAnimationSnapshot implements ToFloatFunction, ObjectFloa final float scale; final boolean looping; float progress; + int loops; public GuiAnimationSnapshot(GuiAnimator animator, IGuiBox box, boolean looping) { this(animator, box.getBaseX(), box.getBaseY(), box.getBaseWidth(), box.getBaseHeight(), box.getBaseScale(), looping); @@ -29,7 +30,7 @@ public class GuiAnimationSnapshot implements ToFloatFunction, ObjectFloa this.scale = scale; this.looping = looping; } - + @Override public float applyAsFloat(Target k) { return switch(k) { @@ -53,6 +54,10 @@ public class GuiAnimationSnapshot implements ToFloatFunction, ObjectFloa } } + public int loops() { + return loops; + } + public GuiAnimationSnapshot applyDifference(GuiComponent component) { for(Target target : Target.values()) { animator.accept(target, applyAsFloat(target) - target.get(component)); @@ -66,7 +71,8 @@ public class GuiAnimationSnapshot implements ToFloatFunction, ObjectFloa if(progress >= animation.duration()) { if(!looping) return true; progress = 0F; + loops++; } return false; } -} +} \ No newline at end of file diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/animation/GuiAnimator.java b/src/main/java/speiger/src/coreengine/rendering/gui/animation/GuiAnimator.java index a8bb9ea..f2cdc25 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/animation/GuiAnimator.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/animation/GuiAnimator.java @@ -33,6 +33,11 @@ public class GuiAnimator implements ObjectFloatConsumer { return activeAnimations.containsKey(animation); } + public int getLoopAmount(GuiAnimation animation) { + GuiAnimationSnapshot snapshot = activeAnimations.get(animation); + return snapshot == null ? -1 : snapshot.loops(); + } + public void removeAnimation(GuiAnimation animation) { activeAnimations.remove(animation); } diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/animation/IAction.java b/src/main/java/speiger/src/coreengine/rendering/gui/animation/IAction.java index e22c434..a5bdb3f 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/animation/IAction.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/animation/IAction.java @@ -10,6 +10,7 @@ public interface IAction { public default IAction withPreDelay(float delay) { return this instanceof PreDelayedAction delayed ? new PreDelayedAction(delayed.action(), delay + delayed.delay()) : new PreDelayedAction(this, delay); } public default IAction withPostDelay(float delay) { return this instanceof PostDelayedAction delayed ? new PostDelayedAction(delayed.action(), delay + delayed.delay()) : new PostDelayedAction(this, delay); } public default IAction reverse() { return this instanceof ReversedAction reversed ? reversed.action() : new ReversedAction(this); } + public default IAction asLoop() { return this instanceof LoopingAction loop ? loop : new LoopingAction(this); } public record PreDelayedAction(IAction action, float delay) implements IAction { @Override @@ -38,5 +39,13 @@ public interface IAction { } } - + public record LoopingAction(IAction action) implements IAction { + @Override + public float duration() { return action.duration() * 2F; } + @Override + public void apply(Target target, ToFloatFunction getter, ObjectFloatConsumer setter, float progress) { + float duration = action.duration(); + action.apply(target, getter, setter, progress >= duration ? duration - (progress - duration) : progress); + } + } } \ No newline at end of file diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/animation/actions/EasedAction.java b/src/main/java/speiger/src/coreengine/rendering/gui/animation/actions/EasedAction.java new file mode 100644 index 0000000..428e445 --- /dev/null +++ b/src/main/java/speiger/src/coreengine/rendering/gui/animation/actions/EasedAction.java @@ -0,0 +1,27 @@ +package speiger.src.coreengine.rendering.gui.animation.actions; + +import speiger.src.collections.objects.functions.consumer.ObjectFloatConsumer; +import speiger.src.collections.objects.functions.function.ToFloatFunction; +import speiger.src.coreengine.math.MathUtils; +import speiger.src.coreengine.math.misc.IEasing; +import speiger.src.coreengine.rendering.gui.animation.GuiAnimation.Target; +import speiger.src.coreengine.rendering.gui.animation.IAction; + +public class EasedAction implements IAction { + float duration; + float targetValue; + IEasing function; + + public EasedAction(float duration, float targetValue, IEasing function) { + this.duration = duration; + this.targetValue = targetValue; + this.function = function; + } + + @Override + public float duration() { return duration; } + @Override + public void apply(Target target, ToFloatFunction getter, ObjectFloatConsumer setter, float progress) { + setter.accept(target, MathUtils.lerp(getter.applyAsFloat(target), targetValue, (float)function.ease(progress, duration))); + } +}