Better animation system

This commit is contained in:
2026-02-22 00:12:13 +01:00
parent e62da29a49
commit f952fa7095
11 changed files with 33 additions and 115 deletions
@@ -41,6 +41,12 @@ public class Element {
public void mouseReleased(double mouseX, double mouseY, int button) {
}
public void playAnimationFrame(long elapsed) {
if (this.animation != null) {
this.animation.tick(this.curve.apply(Math.min(1.0, (double) elapsed / this.animation.duration)), this);
}
}
public Element dimensions(int width, int height) {
this.width = width;
this.height = height;
@@ -4,13 +4,15 @@ public class ElementContext {
public int mouseX, mouseY;
public int elementWidth, elementHeight;
public float elementScale;
public long elapsed;
public ElementContext(int mouseX, int mouseY, Element e) {
public ElementContext(long elapsed, int mouseX, int mouseY, Element e) {
this.mouseX = mouseX - e.x;
this.mouseY = mouseY - e.y;
this.elementWidth = e.width;
this.elementHeight = e.height;
this.elementScale = e.scale;
this.elapsed = elapsed;
}
public boolean isHovering() {
@@ -1,11 +1,11 @@
package org.saturnclient.ui2;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import org.saturnclient.saturnclient.mixin.DrawContextAccessor;
import org.saturnclient.ui2.anim.Animation;
import org.saturnclient.ui2.anim.SlideXAbsolute;
import org.saturnclient.ui2.components.ElementRenderer;
import net.minecraft.client.MinecraftClient;
@@ -23,6 +23,7 @@ public abstract class SaturnScreen extends Screen {
private final Pool pool = new Pool(3);
protected List<Element> elements = new ArrayList<>();
protected float backgroundOpacity = 1.0f;
protected Instant start = null;
public int blurDuration = 700;
public float blurProgress = 0.0f;
public int backgroundBlur = 10;
@@ -41,36 +42,7 @@ public abstract class SaturnScreen extends Screen {
}
public void draw(Element element) {
synchronized (elements) {
elements.add(element);
}
if (element.animation != null) {
element.animation.init(element);
Animation.execute((Float progress) -> {
element.animation.tick(progress, element);
}, element.animation.duration);
}
if (element.duration != null) {
new Thread(() -> {
try {
Animation fadeOut = new SlideXAbsolute(700, -(width - element.x));
Thread.sleep(element.duration);
fadeOut.init(element);
Animation.executeSync((Float progress) -> {
fadeOut.tick(progress, element);
}, fadeOut.duration);
synchronized (elements) {
elements.remove(element);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
ElementRenderer.draw(elements, element);
}
@Override
@@ -79,10 +51,6 @@ public abstract class SaturnScreen extends Screen {
width *= 2;
height *= 2;
ui(); // abstraction to render the saturn ui and also render extra stuff here
Animation.execute((Float progress) -> {
blurProgress = progress;
}, blurDuration);
}
public abstract void ui();
@@ -90,6 +58,11 @@ public abstract class SaturnScreen extends Screen {
@SuppressWarnings("deprecation")
@Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
if (start == null) {
start = Instant.now();
}
long elapsed = Duration.between(start, Instant.now()).toMillis();
mouseX *= 2;
mouseY *= 2;
@@ -114,7 +87,7 @@ public abstract class SaturnScreen extends Screen {
renderScope.matrices.scale(0.5f, 0.5f, 0.5f);
ElementRenderer.render(new ArrayList<>(elements), renderScope, mouseX, mouseY);
ElementRenderer.render(new ArrayList<>(elements), elapsed, renderScope, mouseX, mouseY);
renderScope.matrices.pop();
}
@@ -1,8 +1,5 @@
package org.saturnclient.ui2.anim;
import java.util.function.Consumer;
import java.util.function.Function;
import org.saturnclient.ui2.Element;
public abstract class Animation {
@@ -12,64 +9,7 @@ public abstract class Animation {
this.duration = duration;
}
public abstract void tick(float progress, Element element);
public abstract void tick(double progress, Element element);
public abstract void init(Element element);
public static void execute(Consumer<Float> tick, int duration) {
new Thread(() -> {
Function<Double, Double> curveFunction = Curve::easeInOutCubic;
float progress = 0.0f;
double incremental = (1000 - duration) / 10000.0;
for (int i = 0; i <= 100; i++) {
float newProgress = (float) (double) curveFunction.apply(i / 100.0);
while (Math.abs(newProgress - progress) > 1e-6) {
if (progress < newProgress) {
progress += incremental;
if (progress > newProgress) progress = newProgress;
} else {
progress -= incremental;
if (progress < newProgress) progress = newProgress;
}
tick.accept(newProgress);
try {
Thread.sleep(duration / 100);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}).start();
}
public static void executeSync(Consumer<Float> tick, int duration) {
Function<Double, Double> curveFunction = Curve::easeInOutCubic;
float progress = 0.0f;
double incremental = (1000 - duration) / 10000.0;
for (int i = 0; i <= 100; i++) {
float newProgress = (float) (double) curveFunction.apply(i / 100.0);
while (Math.abs(newProgress - progress) > 1e-6) {
if (progress < newProgress) {
progress += incremental;
if (progress > newProgress) progress = newProgress;
} else {
progress -= incremental;
if (progress < newProgress) progress = newProgress;
}
tick.accept(newProgress);
try {
Thread.sleep(duration / 100);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
@@ -10,8 +10,8 @@ public class Fade extends Animation {
}
@Override
public void tick(float progress, Element element) {
element.opacity = targetOpacity * progress;
public void tick(double progress, Element element) {
element.opacity = targetOpacity * (float) progress;
}
@Override
@@ -10,8 +10,8 @@ public class FadeOut extends Animation {
}
@Override
public void tick(float progress, Element element) {
element.opacity = targetOpacity - progress;
public void tick(double progress, Element element) {
element.opacity = targetOpacity - (float) progress;
}
@Override
@@ -24,7 +24,7 @@ public class SlideX extends Animation {
}
@Override
public void tick(float progress, Element element) {
public void tick(double progress, Element element) {
element.x = elementX + (int) (offset * progress);
}
@@ -24,7 +24,7 @@ public class SlideXAbsolute extends Animation {
}
@Override
public void tick(float progress, Element element) {
public void tick(double progress, Element element) {
element.x = elementX + (int) (offset * progress);
}
@@ -26,7 +26,7 @@ public class SlideY extends Animation {
}
@Override
public void tick(float progress, Element element) {
public void tick(double progress, Element element) {
element.y = elementY + (int) (offset * progress);
}
@@ -7,7 +7,6 @@ import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.ElementContext;
import org.saturnclient.ui2.RenderScope;
import org.saturnclient.ui2.Utils;
import org.saturnclient.ui2.anim.Animation;
public class ElementRenderer {
public static void draw(List<Element> elements, Element element) {
@@ -17,20 +16,18 @@ public class ElementRenderer {
if (element.animation != null) {
element.animation.init(element);
Animation.execute((Float progress) -> {
element.animation.tick(progress, element);
}, element.animation.duration);
}
}
public static void render(List<Element> elements, RenderScope renderScope, int mouseX, int mouseY) {
public static void render(List<Element> elements, long elapsed, RenderScope renderScope, int mouseX, int mouseY) {
for (Element element : elements) {
element.playAnimationFrame(elapsed);
renderScope.matrices.push();
renderScope.setOpacity(element.opacity);
renderScope.matrices.translate(element.x, element.y, 0);
renderScope.matrices.scale(element.scale, element.scale, 1.0f);
element.render(renderScope, new ElementContext(mouseX, mouseY, element));
element.render(renderScope, new ElementContext(elapsed, mouseX, mouseY, element));
renderScope.matrices.pop();
renderScope.setRenderLayer(null);
}
@@ -36,7 +36,7 @@ public class Scroll extends Element {
renderScope.matrices.push();
renderScope.matrices.translate(padding, -scroll + padding, 0);
ElementRenderer.render(children, renderScope,
ElementRenderer.render(children, ctx.elapsed, renderScope,
ctx.mouseX - padding,
ctx.mouseY - padding + scroll);