Added Easing functions for the gui Animations

This commit is contained in:
Speiger 2024-06-05 22:54:37 +02:00
parent cab2095668
commit 9526fe42b9
8 changed files with 123 additions and 3 deletions

3
TESTS_TO_DO.md Normal file
View File

@ -0,0 +1,3 @@
# Tests that should be done.
- Test starting animations with delays of each other to see if they act properly.

View File

@ -5,6 +5,7 @@ public class MathUtils {
private static final float[] COS_TABLE; private static final float[] COS_TABLE;
private static final float TABLE_MASK; private static final float TABLE_MASK;
private static final int SIN_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 final double PI_INVERSION = 180D / Math.PI;
public static float sin(float a) { public static float sin(float a) {

View File

@ -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;
}
}

View File

@ -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));
}
}

View File

@ -15,6 +15,7 @@ public class GuiAnimationSnapshot implements ToFloatFunction<Target>, ObjectFloa
final float scale; final float scale;
final boolean looping; final boolean looping;
float progress; float progress;
int loops;
public GuiAnimationSnapshot(GuiAnimator animator, IGuiBox box, boolean looping) { public GuiAnimationSnapshot(GuiAnimator animator, IGuiBox box, boolean looping) {
this(animator, box.getBaseX(), box.getBaseY(), box.getBaseWidth(), box.getBaseHeight(), box.getBaseScale(), looping); this(animator, box.getBaseX(), box.getBaseY(), box.getBaseWidth(), box.getBaseHeight(), box.getBaseScale(), looping);
@ -53,6 +54,10 @@ public class GuiAnimationSnapshot implements ToFloatFunction<Target>, ObjectFloa
} }
} }
public int loops() {
return loops;
}
public GuiAnimationSnapshot applyDifference(GuiComponent component) { public GuiAnimationSnapshot applyDifference(GuiComponent component) {
for(Target target : Target.values()) { for(Target target : Target.values()) {
animator.accept(target, applyAsFloat(target) - target.get(component)); animator.accept(target, applyAsFloat(target) - target.get(component));
@ -66,6 +71,7 @@ public class GuiAnimationSnapshot implements ToFloatFunction<Target>, ObjectFloa
if(progress >= animation.duration()) { if(progress >= animation.duration()) {
if(!looping) return true; if(!looping) return true;
progress = 0F; progress = 0F;
loops++;
} }
return false; return false;
} }

View File

@ -33,6 +33,11 @@ public class GuiAnimator implements ObjectFloatConsumer<Target> {
return activeAnimations.containsKey(animation); 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) { public void removeAnimation(GuiAnimation animation) {
activeAnimations.remove(animation); activeAnimations.remove(animation);
} }

View File

@ -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 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 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 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 { public record PreDelayedAction(IAction action, float delay) implements IAction {
@Override @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<Target> getter, ObjectFloatConsumer<Target> setter, float progress) {
float duration = action.duration();
action.apply(target, getter, setter, progress >= duration ? duration - (progress - duration) : progress);
}
}
} }

View File

@ -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<Target> getter, ObjectFloatConsumer<Target> setter, float progress) {
setter.accept(target, MathUtils.lerp(getter.applyAsFloat(target), targetValue, (float)function.ease(progress, duration)));
}
}