forked from Clones/Controlify
minor improvements to carousel
This commit is contained in:
@ -18,10 +18,9 @@ import net.minecraft.client.gui.components.events.GuiEventListener;
|
|||||||
import net.minecraft.client.gui.layouts.FrameLayout;
|
import net.minecraft.client.gui.layouts.FrameLayout;
|
||||||
import net.minecraft.client.gui.layouts.GridLayout;
|
import net.minecraft.client.gui.layouts.GridLayout;
|
||||||
import net.minecraft.client.gui.narration.NarratableEntry;
|
import net.minecraft.client.gui.narration.NarratableEntry;
|
||||||
|
import net.minecraft.client.gui.narration.NarratedElementType;
|
||||||
import net.minecraft.client.gui.narration.NarrationElementOutput;
|
import net.minecraft.client.gui.narration.NarrationElementOutput;
|
||||||
import net.minecraft.client.gui.navigation.FocusNavigationEvent;
|
import net.minecraft.client.gui.navigation.FocusNavigationEvent;
|
||||||
import net.minecraft.client.gui.navigation.ScreenAxis;
|
|
||||||
import net.minecraft.client.gui.navigation.ScreenDirection;
|
|
||||||
import net.minecraft.client.gui.navigation.ScreenRectangle;
|
import net.minecraft.client.gui.navigation.ScreenRectangle;
|
||||||
import net.minecraft.client.gui.screens.Screen;
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
import net.minecraft.client.gui.screens.worldselection.CreateWorldScreen;
|
import net.minecraft.client.gui.screens.worldselection.CreateWorldScreen;
|
||||||
@ -41,11 +40,12 @@ public class ControllerCarouselScreen extends Screen {
|
|||||||
|
|
||||||
private List<CarouselEntry> carouselEntries = null;
|
private List<CarouselEntry> carouselEntries = null;
|
||||||
private int carouselIndex;
|
private int carouselIndex;
|
||||||
private Animator animator;
|
private Animator.AnimationInstance carouselAnimation = null;
|
||||||
|
|
||||||
private ControllerCarouselScreen(Screen parent) {
|
private ControllerCarouselScreen(Screen parent) {
|
||||||
super(Component.translatable("controlify.gui.carousel.title"));
|
super(Component.translatable("controlify.gui.carousel.title"));
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
|
this.carouselIndex = Controlify.instance().getCurrentController().map(c -> ControllerManager.getConnectedControllers().indexOf(c)).orElse(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Screen createConfigScreen(Screen parent) {
|
public static Screen createConfigScreen(Screen parent) {
|
||||||
@ -88,15 +88,26 @@ public class ControllerCarouselScreen extends Screen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void refreshControllers() {
|
public void refreshControllers() {
|
||||||
|
Controller<?, ?> prevSelectedController;
|
||||||
if (carouselEntries != null) {
|
if (carouselEntries != null) {
|
||||||
carouselEntries.forEach(this::removeWidget);
|
carouselEntries.forEach(this::removeWidget);
|
||||||
|
prevSelectedController = carouselEntries.get(carouselIndex).controller;
|
||||||
|
} else {
|
||||||
|
prevSelectedController = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
carouselEntries = ControllerManager.getConnectedControllers().stream()
|
carouselEntries = ControllerManager.getConnectedControllers().stream()
|
||||||
.map(c -> new CarouselEntry(c, this.width / 3, this.height - 66))
|
.map(c -> new CarouselEntry(c, this.width / 3, this.height - 66))
|
||||||
.peek(this::addRenderableWidget)
|
.peek(this::addRenderableWidget)
|
||||||
.toList();
|
.toList();
|
||||||
carouselIndex = Controlify.instance().getCurrentController().map(c -> ControllerManager.getConnectedControllers().indexOf(c)).orElse(0);
|
carouselIndex = carouselEntries.stream()
|
||||||
|
.filter(e -> e.controller == prevSelectedController)
|
||||||
|
.findFirst()
|
||||||
|
.map(carouselEntries::indexOf)
|
||||||
|
.orElse(Controlify.instance().getCurrentController()
|
||||||
|
.map(c -> ControllerManager.getConnectedControllers().indexOf(c))
|
||||||
|
.orElse(0)
|
||||||
|
);
|
||||||
if (!carouselEntries.isEmpty())
|
if (!carouselEntries.isEmpty())
|
||||||
carouselEntries.get(carouselIndex).overlayColor = 0;
|
carouselEntries.get(carouselIndex).overlayColor = 0;
|
||||||
|
|
||||||
@ -119,10 +130,6 @@ public class ControllerCarouselScreen extends Screen {
|
|||||||
graphics.blit(CreateWorldScreen.LIGHT_DIRT_BACKGROUND, 0, 0, 0, 0f, 0f, this.width, footerY, 32, 32);
|
graphics.blit(CreateWorldScreen.LIGHT_DIRT_BACKGROUND, 0, 0, 0, 0f, 0f, this.width, footerY, 32, 32);
|
||||||
graphics.setColor(1f, 1f, 1f, 1f);
|
graphics.setColor(1f, 1f, 1f, 1f);
|
||||||
|
|
||||||
if (animator != null && !animator.isDone()) {
|
|
||||||
animator.tick(delta);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (carouselEntries.isEmpty()) {
|
if (carouselEntries.isEmpty()) {
|
||||||
graphics.drawCenteredString(font, Component.translatable("controlify.gui.carousel.no_controllers"), this.width / 2, (this.height - 36) / 2 - 10, 0xFFAAAAAA);
|
graphics.drawCenteredString(font, Component.translatable("controlify.gui.carousel.no_controllers"), this.width / 2, (this.height - 36) / 2 - 10, 0xFFAAAAAA);
|
||||||
}
|
}
|
||||||
@ -136,25 +143,8 @@ public class ControllerCarouselScreen extends Screen {
|
|||||||
graphics.blit(CreateWorldScreen.LIGHT_DIRT_BACKGROUND, 0, 0, 0, 0.0F, 0.0F, this.width, this.height, scale, scale);
|
graphics.blit(CreateWorldScreen.LIGHT_DIRT_BACKGROUND, 0, 0, 0, 0.0F, 0.0F, this.width, this.height, scale, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
|
|
||||||
switch (keyCode) {
|
|
||||||
case InputConstants.KEY_RIGHT -> {
|
|
||||||
if (carouselEntries.stream().anyMatch(CarouselEntry::isFocused))
|
|
||||||
focusOnEntry(Math.min(carouselEntries.size() - 1, carouselIndex + 1));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case InputConstants.KEY_LEFT -> {
|
|
||||||
if (carouselEntries.stream().anyMatch(CarouselEntry::isFocused))
|
|
||||||
focusOnEntry(Math.max(0, carouselIndex - 1));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return super.keyPressed(keyCode, scanCode, modifiers);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void focusOnEntry(int index) {
|
public void focusOnEntry(int index) {
|
||||||
if (animator != null && !animator.isDone())
|
if (carouselAnimation != null && !carouselAnimation.isDone())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int diff = index - carouselIndex;
|
int diff = index - carouselIndex;
|
||||||
@ -162,13 +152,14 @@ public class ControllerCarouselScreen extends Screen {
|
|||||||
|
|
||||||
carouselIndex = index;
|
carouselIndex = index;
|
||||||
|
|
||||||
animator = new Animator(10, x -> x < 0.5f ? 4 * x * x * x : 1 - (float)Math.pow(-2 * x + 2, 3) / 2);
|
carouselAnimation = new Animator.AnimationInstance(10, x -> x < 0.5f ? 4 * x * x * x : 1 - (float)Math.pow(-2 * x + 2, 3) / 2);
|
||||||
for (CarouselEntry entry : carouselEntries) {
|
for (CarouselEntry entry : carouselEntries) {
|
||||||
boolean selected = carouselEntries.indexOf(entry) == index;
|
boolean selected = carouselEntries.indexOf(entry) == index;
|
||||||
animator.addConsumer(entry::setX, entry.getX(), entry.getX() + -diff * (this.width / 2f));
|
carouselAnimation.addConsumer(entry::setX, entry.getX(), entry.getX() + -diff * (this.width / 2f));
|
||||||
animator.addConsumer(entry::setY, entry.getY(), selected ? 20f : 10f);
|
carouselAnimation.addConsumer(entry::setY, entry.getY(), selected ? 20f : 10f);
|
||||||
animator.addConsumer(t -> entry.overlayColor = FastColor.ARGB32.lerp(t, entry.overlayColor, selected ? 0 : 0x90000000), 0f, 1f);
|
carouselAnimation.addConsumer(t -> entry.overlayColor = FastColor.ARGB32.lerp(t, entry.overlayColor, selected ? 0 : 0x90000000), 0f, 1f);
|
||||||
}
|
}
|
||||||
|
Animator.INSTANCE.play(carouselAnimation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -179,18 +170,23 @@ public class ControllerCarouselScreen extends Screen {
|
|||||||
private class CarouselEntry extends AbstractContainerEventHandler implements Renderable, NarratableEntry {
|
private class CarouselEntry extends AbstractContainerEventHandler implements Renderable, NarratableEntry {
|
||||||
private int x, y;
|
private int x, y;
|
||||||
private final int width, height;
|
private final int width, height;
|
||||||
|
|
||||||
private float translationX, translationY;
|
private float translationX, translationY;
|
||||||
|
|
||||||
private final Controller<?, ?> controller;
|
private final Controller<?, ?> controller;
|
||||||
private final boolean hasNickname;
|
private final boolean hasNickname;
|
||||||
|
|
||||||
private Button useControllerButton;
|
private final Button useControllerButton;
|
||||||
private Button settingsButton;
|
private final Button settingsButton;
|
||||||
private ImmutableList<? extends GuiEventListener> children;
|
private final ImmutableList<? extends GuiEventListener> children;
|
||||||
|
|
||||||
|
private boolean prevUse;
|
||||||
|
private float currentlyUsedPos;
|
||||||
|
private Animator.AnimationInstance currentlyUsedAnimation;
|
||||||
|
|
||||||
private int overlayColor = 0x90000000;
|
private int overlayColor = 0x90000000;
|
||||||
|
|
||||||
|
private boolean hovered = false;
|
||||||
|
|
||||||
private CarouselEntry(Controller<?, ?> controller, int width, int height) {
|
private CarouselEntry(Controller<?, ?> controller, int width, int height) {
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
@ -201,10 +197,17 @@ public class ControllerCarouselScreen extends Screen {
|
|||||||
this.settingsButton = Button.builder(Component.translatable("controlify.gui.carousel.entry.settings"), btn -> minecraft.setScreen(ControllerConfigGui.generateConfigScreen(ControllerCarouselScreen.this, controller))).width(getWidth() / 2 - 4).build();
|
this.settingsButton = Button.builder(Component.translatable("controlify.gui.carousel.entry.settings"), btn -> minecraft.setScreen(ControllerConfigGui.generateConfigScreen(ControllerCarouselScreen.this, controller))).width(getWidth() / 2 - 4).build();
|
||||||
this.useControllerButton = Button.builder(Component.translatable("controlify.gui.carousel.entry.use"), btn -> Controlify.instance().setCurrentController(controller)).width(settingsButton.getWidth()).build();
|
this.useControllerButton = Button.builder(Component.translatable("controlify.gui.carousel.entry.use"), btn -> Controlify.instance().setCurrentController(controller)).width(settingsButton.getWidth()).build();
|
||||||
this.children = ImmutableList.of(settingsButton, useControllerButton);
|
this.children = ImmutableList.of(settingsButton, useControllerButton);
|
||||||
|
|
||||||
|
this.prevUse = isCurrentlyUsed();
|
||||||
|
this.currentlyUsedPos = prevUse ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) {
|
public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) {
|
||||||
|
hovered = isMouseOver(mouseX, mouseY);
|
||||||
|
|
||||||
|
graphics.enableScissor(x, y, x + width + (translationX > 0 ? 1 : 0), y + height + (translationY > 0 ? 1 : 0));
|
||||||
|
|
||||||
graphics.pose().pushPose();
|
graphics.pose().pushPose();
|
||||||
graphics.pose().translate(translationX, translationY, 0);
|
graphics.pose().translate(translationX, translationY, 0);
|
||||||
|
|
||||||
@ -222,10 +225,15 @@ public class ControllerCarouselScreen extends Screen {
|
|||||||
controller.config().customName = nickname;
|
controller.config().customName = nickname;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Controlify.instance().getCurrentController().orElse(null) == controller) {
|
Component currentlyInUseText = Component.translatable("controlify.gui.carousel.entry.in_use").withStyle(ChatFormatting.GREEN);
|
||||||
|
graphics.pose().pushPose();
|
||||||
|
graphics.pose().translate((4 + 9 + 4 + font.width(currentlyInUseText)) * currentlyUsedPos, 0, 0);
|
||||||
|
|
||||||
|
if (currentlyUsedPos > -1) {
|
||||||
graphics.blit(CHECKMARK, x + 4, y + 4, 0f, 0f, 9, 8, 9, 8);
|
graphics.blit(CHECKMARK, x + 4, y + 4, 0f, 0f, 9, 8, 9, 8);
|
||||||
graphics.drawString(font, Component.translatable("controlify.gui.carousel.entry.in_use").withStyle(ChatFormatting.GREEN), x + 17, y + 4, -1);
|
graphics.drawString(font, currentlyInUseText, x + 17, y + 4, -1);
|
||||||
}
|
}
|
||||||
|
graphics.pose().popPose();
|
||||||
|
|
||||||
int iconWidth = width - 6;
|
int iconWidth = width - 6;
|
||||||
// buttons 4px padding top currently in use controller name image padding
|
// buttons 4px padding top currently in use controller name image padding
|
||||||
@ -236,11 +244,22 @@ public class ControllerCarouselScreen extends Screen {
|
|||||||
graphics.pose().translate(x + width / 2 - iconSize / 2, y + font.lineHeight + 12 + iconHeight / 2 - iconSize / 2, 0);
|
graphics.pose().translate(x + width / 2 - iconSize / 2, y + font.lineHeight + 12 + iconHeight / 2 - iconSize / 2, 0);
|
||||||
graphics.pose().scale(iconSize / 64f, iconSize / 64f, 1);
|
graphics.pose().scale(iconSize / 64f, iconSize / 64f, 1);
|
||||||
graphics.blit(controller.icon(), 0, 0, 0f, 0f, 64, 64, 64, 64);
|
graphics.blit(controller.icon(), 0, 0, 0f, 0f, 64, 64, 64, 64);
|
||||||
|
graphics.pose().popPose();
|
||||||
|
|
||||||
graphics.pose().translate(0, 0, 1);
|
graphics.pose().translate(0, 0, 1);
|
||||||
graphics.fill(x, y, x + width, y + height, overlayColor);
|
graphics.fill(x, y, x + width, y + height, overlayColor);
|
||||||
|
|
||||||
graphics.pose().popPose();
|
graphics.pose().popPose();
|
||||||
|
|
||||||
|
graphics.disableScissor();
|
||||||
|
|
||||||
|
if (prevUse != isCurrentlyUsed()) {
|
||||||
|
if (currentlyUsedAnimation != null)
|
||||||
|
currentlyUsedAnimation.finish();
|
||||||
|
currentlyUsedAnimation = Animator.INSTANCE.play(new Animator.AnimationInstance(20, t -> 1 - (float)Math.pow(1 - t, 5))
|
||||||
|
.addConsumer(t -> currentlyUsedPos = t, currentlyUsedPos, isCurrentlyUsed() ? 0 : -1));
|
||||||
|
}
|
||||||
|
prevUse = isCurrentlyUsed();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -248,7 +267,7 @@ public class ControllerCarouselScreen extends Screen {
|
|||||||
if (mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height) {
|
if (mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height) {
|
||||||
int index = carouselEntries.indexOf(this);
|
int index = carouselEntries.indexOf(this);
|
||||||
if (index != carouselIndex) {
|
if (index != carouselIndex) {
|
||||||
if (animator == null || animator.isDone())
|
if (carouselAnimation == null || carouselAnimation.isDone())
|
||||||
focusOnEntry(index);
|
focusOnEntry(index);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -304,7 +323,7 @@ public class ControllerCarouselScreen extends Screen {
|
|||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public ComponentPath nextFocusPath(FocusNavigationEvent event) {
|
public ComponentPath nextFocusPath(FocusNavigationEvent event) {
|
||||||
if (animator != null && !animator.isDone())
|
if (carouselAnimation != null && !carouselAnimation.isDone())
|
||||||
return null;
|
return null;
|
||||||
return super.nextFocusPath(event);
|
return super.nextFocusPath(event);
|
||||||
}
|
}
|
||||||
@ -314,14 +333,19 @@ public class ControllerCarouselScreen extends Screen {
|
|||||||
return new ScreenRectangle(x, y, width, height);
|
return new ScreenRectangle(x, y, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isCurrentlyUsed() {
|
||||||
|
return Controlify.instance().getCurrentController().orElse(null) == controller;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NarrationPriority narrationPriority() {
|
public NarrationPriority narrationPriority() {
|
||||||
return NarrationPriority.NONE;
|
return isFocused() ? NarrationPriority.FOCUSED : hovered ? NarrationPriority.HOVERED : NarrationPriority.NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateNarration(NarrationElementOutput builder) {
|
public void updateNarration(NarrationElementOutput builder) {
|
||||||
|
builder.add(NarratedElementType.TITLE, controller.name());
|
||||||
|
builder.add(NarratedElementType.USAGE, Component.literal("Left arrow to go to previous controller, right arrow to go to next controller."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import dev.isxander.controlify.Controlify;
|
|||||||
import dev.isxander.controlify.ControllerManager;
|
import dev.isxander.controlify.ControllerManager;
|
||||||
import dev.isxander.controlify.controller.Controller;
|
import dev.isxander.controlify.controller.Controller;
|
||||||
import dev.isxander.controlify.gui.screen.BetaNoticeScreen;
|
import dev.isxander.controlify.gui.screen.BetaNoticeScreen;
|
||||||
|
import dev.isxander.controlify.utils.Animator;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.components.toasts.ToastComponent;
|
import net.minecraft.client.gui.components.toasts.ToastComponent;
|
||||||
import net.minecraft.client.gui.screens.Screen;
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
@ -57,4 +58,9 @@ public abstract class MinecraftMixin {
|
|||||||
private void onMinecraftClose(CallbackInfo ci) {
|
private void onMinecraftClose(CallbackInfo ci) {
|
||||||
ControllerManager.getConnectedControllers().forEach(Controller::close);
|
ControllerManager.getConnectedControllers().forEach(Controller::close);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Inject(method = "runTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GameRenderer;render(FJZ)V"))
|
||||||
|
private void tickAnimator(boolean tick, CallbackInfo ci) {
|
||||||
|
Animator.INSTANCE.progress(this.getDeltaFrameTime());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,52 +2,92 @@ package dev.isxander.controlify.utils;
|
|||||||
|
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.UnaryOperator;
|
import java.util.function.UnaryOperator;
|
||||||
|
|
||||||
public class Animator {
|
public final class Animator {
|
||||||
private final List<AnimationConsumer> animations;
|
public static final Animator INSTANCE = new Animator();
|
||||||
private final UnaryOperator<Float> easingFunction;
|
|
||||||
private final int durationTicks;
|
|
||||||
private float time;
|
|
||||||
|
|
||||||
public Animator(int durationTicks, UnaryOperator<Float> easingFunction) {
|
private final List<AnimationInstance> animations;
|
||||||
|
|
||||||
|
private Animator() {
|
||||||
this.animations = new ArrayList<>();
|
this.animations = new ArrayList<>();
|
||||||
this.easingFunction = easingFunction;
|
|
||||||
this.durationTicks = durationTicks;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addConsumer(Consumer<Float> consumer, float start, float end) {
|
public void progress(float deltaTime) {
|
||||||
animations.add(new AnimationConsumer(consumer, start, end));
|
animations.forEach(animation -> animation.tick(deltaTime));
|
||||||
|
animations.removeIf(AnimationInstance::isDone);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addConsumer(Consumer<Integer> consumer, int start, int end) {
|
public AnimationInstance play(AnimationInstance animation) {
|
||||||
animations.add(new AnimationConsumer(aFloat -> consumer.accept(aFloat.intValue()), start, end));
|
animations.add(animation);
|
||||||
|
return animation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tick(float deltaTime) {
|
public static class AnimationInstance {
|
||||||
time += deltaTime;
|
private final List<AnimationConsumer> animations;
|
||||||
if (time > durationTicks) {
|
private final UnaryOperator<Float> easingFunction;
|
||||||
time = durationTicks;
|
private final int durationTicks;
|
||||||
|
private float time;
|
||||||
|
private boolean done;
|
||||||
|
private final List<Runnable> callbacks = new ArrayList<>();
|
||||||
|
|
||||||
|
public AnimationInstance(int durationTicks, UnaryOperator<Float> easingFunction) {
|
||||||
|
this.animations = new ArrayList<>();
|
||||||
|
this.easingFunction = easingFunction;
|
||||||
|
this.durationTicks = durationTicks;
|
||||||
}
|
}
|
||||||
updateConsumers();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateConsumers() {
|
public AnimationInstance addConsumer(Consumer<Float> consumer, float start, float end) {
|
||||||
animations.forEach(consumer -> {
|
animations.add(new AnimationConsumer(consumer, start, end));
|
||||||
float progress = easingFunction.apply(time / durationTicks);
|
return this;
|
||||||
float value = Mth.lerp(progress, consumer.start, consumer.end);
|
}
|
||||||
consumer.consumer.accept(value);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDone() {
|
public AnimationInstance addConsumer(Consumer<Integer> consumer, int start, int end) {
|
||||||
return time >= durationTicks;
|
animations.add(new AnimationConsumer(aFloat -> consumer.accept(aFloat.intValue()), start, end));
|
||||||
}
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
private record AnimationConsumer(Consumer<Float> consumer, float start, float end) {
|
public AnimationInstance onComplete(Runnable callback) {
|
||||||
|
callbacks.add(callback);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tick(float deltaTime) {
|
||||||
|
time += deltaTime;
|
||||||
|
if (time > durationTicks) {
|
||||||
|
if (!done) {
|
||||||
|
callbacks.removeIf(callback -> {
|
||||||
|
callback.run();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
done = true;
|
||||||
|
time = durationTicks;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateConsumers();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateConsumers() {
|
||||||
|
animations.forEach(consumer -> {
|
||||||
|
float progress = easingFunction.apply(time / durationTicks);
|
||||||
|
float value = Mth.lerp(progress, consumer.start, consumer.end);
|
||||||
|
consumer.consumer.accept(value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void finish() {
|
||||||
|
time = durationTicks;
|
||||||
|
updateConsumers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDone() {
|
||||||
|
return done;
|
||||||
|
}
|
||||||
|
|
||||||
|
private record AnimationConsumer(Consumer<Float> consumer, float start, float end) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user