working animations

This commit is contained in:
2025-04-29 01:10:10 +02:00
parent c0b088bb8a
commit d16b66945f
8 changed files with 82 additions and 225 deletions
@@ -1,11 +1,14 @@
package org.saturnclient.ui2;
import org.saturnclient.ui2.anim.Animation;
public class Element {
public int x;
public int y;
public int width;
public int height;
public boolean focused;
public Animation animation;
public void render(RenderScope renderScope, RenderContext ctx) {
}
@@ -40,4 +43,10 @@ public class Element {
return this;
}
public final Element animation(Animation animation) {
this.animation = animation;
return this;
}
}
@@ -1,16 +1,12 @@
package org.saturnclient.ui2;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.config.ThemeManager;
import org.saturnclient.saturnclient.mixin.DrawContextAccessor;
import org.saturnclient.ui2.anim.Animation;
import org.saturnclient.ui2.anim.Curve;
import org.saturnclient.ui2.anim.SlideUp;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.Screen;
@@ -25,41 +21,61 @@ public class SaturnScreen extends Screen {
}
public void draw(Element element) {
Animation animation = new SlideUp();
// Function<Float, Integer> curve = Curve::easeIn;
int duration = 500;
synchronized (elements) {
elements.add(element);
}
if (element.animation != null) {
element.animation.init(element);
new Thread(() -> {
Function<Double, Double> curveFunction = Curve::easeInOutCubicReverse;
int delay = (element.animation.duration / 20) - 15;
long startTime = System.currentTimeMillis();
float lastProgress = 0.0f;
// new Thread(() -> {
// boolean running = true;
// Instant start = Instant.now();
// int tick = 0;
// while (running) {
// if (animation != null) {
// int elapsedMs = (int) java.time.Duration.between(start, Instant.now()).toMillis();
while (true) {
int elapsed = (int) (System.currentTimeMillis() - startTime);
// if (elapsedMs > duration) {
// running = false;
// }
float progress = Math.round(curveFunction.apply((double) elapsed / element.animation.duration) * 1000.0f) / 1000.0f;
// float progress = animation.tick(tick, element);
float p = lastProgress;
// SaturnClient.LOGGER.info("ms: " + curve.apply(progress) + ", Progress: " + progress);
// try {
// Thread.sleep(30);
// } catch (Exception e) {
// }
// tick++;
// } else {
// running = false;
// }
// }
// }).start();
while (progress != p) {
if (p < progress) {
p += 0.01f;
if (p > progress) p = progress;
} else if (p > progress) {
p -= 0.01f;
if (p < progress) p = progress;
}
element.animation.tick(p, element);
try {
Thread.sleep(4);
} catch (Exception e) {
e.printStackTrace();
}
}
if (elapsed > (element.animation.duration + 30)) {
break;
}
if (progress != lastProgress) {
lastProgress = p;
}
if (delay > 0) {
try {
Thread.sleep(delay);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}).start();
}
}
@Override
@@ -3,5 +3,12 @@ package org.saturnclient.ui2.anim;
import org.saturnclient.ui2.Element;
public abstract class Animation {
public abstract float tick(int tick, Element element);
public int duration;
Animation(int duration) {
this.duration = duration;
}
public abstract void tick(float progress, Element element);
public abstract void init(Element element);
}
@@ -1,85 +1,11 @@
package org.saturnclient.ui2.anim;
import java.time.Instant;
import java.util.function.Function;
import org.saturnclient.saturnclient.SaturnClient;
public class Curve {
// Define the curve functions (ease-in, ease-out, ease-in-out)
public static int easeIn(float progress, long elapsedTime, float totalDuration) {
// Ease-in: Modify the curve based on elapsed time
float t = progress;
t *= t; // Ease-in: t^2
// Scale the delay based on the remaining time
return (int) ((t * (totalDuration - elapsedTime)) / totalDuration);
public static double easeInOutCubic(double x) {
return (x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2);
}
public static int easeOut(float progress, long elapsedTime, float totalDuration) {
// Ease-out: Modify the curve based on elapsed time
float t = progress;
t = 1 - (1 - t) * (1 - t); // Ease-out: 1 - (1 - t)^2
// Scale the delay based on the remaining time
return (int) ((t * (totalDuration - elapsedTime)) / totalDuration);
}
public static int easeInOut(float progress, long elapsedTime, float totalDuration) {
// Ease-in-out: Modify the curve based on elapsed time
double t = progress;
if (t < 0.5) {
t = 2 * t * t; // Ease-in: t^2
} else {
t = 1 - Math.pow(-2 * t + 2, 2) / 2; // Ease-out: 1 - (2t-2)^2 / 2
}
// Scale the delay based on the remaining time
return (int) ((t * (totalDuration - elapsedTime)) / totalDuration);
}
public static void animate(float totalDuration, float increment) {
long startTime = System.currentTimeMillis();
float progress = 0.0f;
float progressPerStep = increment;
long elapsedTime = 0; // Track the total elapsed time
// Animation loop until progress reaches 1.0
while (progress < 1.0f) {
// Calculate the current progress value
progress = Math.min(progress + progressPerStep, 1.0f); // Ensure progress does not exceed 1.0
// Calculate the elapsed time
elapsedTime = System.currentTimeMillis() - startTime;
// Calculate the delay based on the current progress and elapsed time using the easing function
// We switch between easeIn, easeOut, and easeInOut for different effects
int delay = easeInOut(progress, elapsedTime, totalDuration);
// Print the progress and delay for debugging
System.out.println("Progress: " + (progress * 100) + "%, Delay: " + delay + "ms");
// Ensure we don't sleep for a negative value
if (delay < 1) {
delay = 1; // Avoid immediate jumps, ensure some delay for visual effect
}
// Sleep for the delay calculated by the easing function
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
e.printStackTrace();
}
// If the elapsed time exceeds the total duration, break out of the loop
if (elapsedTime >= totalDuration) {
break;
}
}
System.out.println("Animation Complete!");
}
public static void main(String[] args) {
float durationInMillis = 500.0f; // Total duration of the animation in ms
float increment = 0.01f; // Increment the progress by 1% each step
animate(durationInMillis, increment); // Start the animation
public static double easeInOutCubicReverse(double x) {
return -(x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2);
}
}
@@ -1,20 +0,0 @@
package org.saturnclient.ui2.anim;
import org.saturnclient.ui2.Element;
public class SlideUp extends Animation {
int targetY;
@Override
public float tick(int tick, Element element) {
if (tick == 0) {
targetY = element.y;
element.y += 20;
} else if (element.y > targetY) {
element.y--;
return ((float) element.y) / targetY;
}
return 0.1f;
}
}
@@ -10,6 +10,7 @@ import org.saturnclient.ui2.SaturnScreen;
import org.saturnclient.ui2.elements.Button;
import org.saturnclient.ui2.elements.ImageTexture;
import org.saturnclient.ui2.elements.TextureButton;
import org.saturnclient.ui2.anim.SlideY;
public class ShiftMenu extends SaturnScreen {
public ShiftMenu() {
@@ -18,21 +19,21 @@ public class ShiftMenu extends SaturnScreen {
@Override
public void ui() {
draw(new ImageTexture(Textures.LOGO).dimensions(49, 49).centerOffset(width, height, 0, -45));
// draw(new ImageTexture(Textures.LOGO_TEXT).dimensions(49, 8).centerOffset(width, height, 0, -23));
draw(new ImageTexture(Textures.LOGO).dimensions(49, 49).centerOffset(width, height, 0, -45).animation(new SlideY(300)));
draw(new ImageTexture(Textures.LOGO_TEXT).dimensions(49, 8).centerOffset(width, height, 0, -23));
// Element button = new Button("Settings", () -> {
// SaturnClient.client.setScreen(new ModMenu());
// }).center(width, height);
Element button = new Button("Settings", () -> {
SaturnClient.client.setScreen(new ModMenu());
}).center(width, height);
// draw(button);
draw(button);
// draw(new TextureButton(Textures.COSMETICS, () -> {
// client.setScreen(new CloaksMenu());
// }).dimensions(button.height, button.height).centerOffset(width, height, (button.width / 2) + (button.height / 2) + 4, 0));
draw(new TextureButton(Textures.COSMETICS, () -> {
client.setScreen(new CloaksMenu());
}).dimensions(button.height, button.height).centerOffset(width, height, (button.width / 2) + (button.height / 2) + 4, 0));
// draw(new TextureButton(Textures.HUD_ICON, () -> {
// client.setScreen(new HudEditor());
// }).dimensions(button.height, button.height).centerOffset(width, height, -((button.width / 2) + (button.height / 2) + 4), 0));
draw(new TextureButton(Textures.HUD_ICON, () -> {
client.setScreen(new HudEditor());
}).dimensions(button.height, button.height).centerOffset(width, height, -((button.width / 2) + (button.height / 2) + 4), 0));
}
}
@@ -1,48 +0,0 @@
package org.test.test;
import java.util.function.Function;
public class AnimationExample {
public static void main(String[] args) {
long stime = System.currentTimeMillis();
Function<Float, Float> curveFunction = CurveFunctions::easeOut;
int duration = 300;
int delayOnProgress = duration / 4;
// 0.1 -> 0.5 = +=0.01
float progress = 0f;
while (System.currentTimeMillis() - stime < duration) {
float newProgress = Math.min(1.0f, curveFunction.apply(progress + 0.05f));
if (newProgress == progress) {
newProgress += 0.05;
}
while (progress != newProgress) {
if (progress > newProgress) {
progress -= 0.05;
if (progress < newProgress) progress = newProgress;
} else if (progress < newProgress) {
progress += 0.05;
if (progress > newProgress) progress = newProgress;
} else {
progress += 0.05;
}
}
System.out.println("New Progress: " + progress);
}
System.out.println((System.currentTimeMillis() - stime) + "ms");
}
// Define the EasingFunction interface (to be passed to functions like easeInOut)
@FunctionalInterface
public interface EasingFunction {
double apply(double t); // Apply the easing function to the normalized progress
}
}
@@ -1,34 +0,0 @@
package org.test.test;
public class CurveFunctions {
public static float linear(float t) {
return t;
}
public static float easeIn(float t) {
return t * t;
}
public static float easeOut(float t) {
return (float)(1 - Math.pow(1 - t, 2));
}
public static float easeInOut(float t) {
return (float)((-Math.cos(Math.PI * t) / 2.0) + 0.5);
}
public static float bounceOut(float t) {
if (t < (1/2.75f)) {
return 7.5625f * t * t;
} else if (t < (2/2.75f)) {
t -= (1.5f/2.75f);
return 7.5625f * t * t + 0.75f;
} else if (t < (2.5/2.75)) {
t -= (2.25f/2.75f);
return 7.5625f * t * t + 0.9375f;
} else {
t -= (2.625f/2.75f);
return 7.5625f * t * t + 0.984375f;
}
}
}