From 4bf54b7cf53a09895091bc1ec84b8a55147849be Mon Sep 17 00:00:00 2001 From: Almas Baimagambetov Date: Tue, 14 Mar 2023 19:27:09 +0000 Subject: [PATCH] feat: AnimationTexture can start from a given frame, part of #1244, co-author: @chengenzhao --- .../almasb/fxgl/texture/AnimatedTexture.kt | 22 ++- .../animation/AnimatedTextureSample.java | 128 ++++++++++++++++++ 2 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 fxgl-samples/src/main/java/intermediate/animation/AnimatedTextureSample.java diff --git a/fxgl-core/src/main/kotlin/com/almasb/fxgl/texture/AnimatedTexture.kt b/fxgl-core/src/main/kotlin/com/almasb/fxgl/texture/AnimatedTexture.kt index 435be78890..f6f9146028 100644 --- a/fxgl-core/src/main/kotlin/com/almasb/fxgl/texture/AnimatedTexture.kt +++ b/fxgl-core/src/main/kotlin/com/almasb/fxgl/texture/AnimatedTexture.kt @@ -50,7 +50,7 @@ class AnimatedTexture(defaultChannel: AnimationChannel) : Texture(defaultChannel /** * Plays given animation [channel] from start to end once. - * The animation will stop at the last frame. + * The animation will stop on the last frame. */ fun playAnimationChannel(channel: AnimationChannel) { animationChannel = channel @@ -60,6 +60,17 @@ class AnimatedTexture(defaultChannel: AnimationChannel) : Texture(defaultChannel animation.start() } + /** + * Plays given animation [channel] from specific [startFrame] to end once. + * The animation will stop on the last frame. + */ + fun playAnimationChannel(channel: AnimationChannel, startFrame: Int) { + playAnimationChannel(channel) + + currentFrame = startFrame + animation.setTimeTo(currentFrame.toDouble() * animationChannel.frameDuration) + } + /** * Loops given [channel]. * @@ -117,6 +128,15 @@ class AnimatedTexture(defaultChannel: AnimationChannel) : Texture(defaultChannel return this } + /** + * Play the last animation channel (or default) from specific [startFrame] to end once. + * The animation will stop on the last frame. + */ + fun playFrom(startFrame: Int): AnimatedTexture { + playAnimationChannel(animationChannel, startFrame) + return this + } + /** * Loops the last animation channel (or default). */ diff --git a/fxgl-samples/src/main/java/intermediate/animation/AnimatedTextureSample.java b/fxgl-samples/src/main/java/intermediate/animation/AnimatedTextureSample.java new file mode 100644 index 0000000000..b8616a0fd3 --- /dev/null +++ b/fxgl-samples/src/main/java/intermediate/animation/AnimatedTextureSample.java @@ -0,0 +1,128 @@ +/* + * FXGL - JavaFX Game Library. The MIT License (MIT). + * Copyright (c) AlmasB (almaslvl@gmail.com). + * See LICENSE for details. + */ + +package intermediate.animation; + +import com.almasb.fxgl.animation.Interpolators; +import com.almasb.fxgl.app.GameApplication; +import com.almasb.fxgl.app.GameSettings; +import com.almasb.fxgl.texture.AnimatedTexture; +import com.almasb.fxgl.texture.AnimationChannel; +import javafx.animation.Interpolator; +import javafx.scene.control.Button; +import javafx.scene.control.Spinner; +import javafx.scene.layout.VBox; +import javafx.scene.paint.Color; +import javafx.scene.text.Font; +import javafx.util.Duration; + +import static com.almasb.fxgl.dsl.FXGL.*; + +/** + * @author Almas Baimagambetov (almaslvl@gmail.com) + */ +public class AnimatedTextureSample extends GameApplication { + @Override + protected void initSettings(GameSettings settings) { + settings.setWidth(1480); + settings.setHeight(1020); + } + + @Override + protected void initGame() { + getGameScene().setBackgroundColor(Color.BLACK); + + var interpolators = Interpolators.values(); + + for (int i = 0; i < interpolators.length; i++) { + var x = i % 7; + var y = i / 7; + + spawnRobot(x * 150, y * 360, interpolators[i].EASE_OUT(), interpolators[i].toString()); + } + + spawnRobot(0, 360 * 2, false, false); + spawnRobot(160, 360 * 2, true, false); + spawnRobot(320, 360 * 2, false, true); + spawnRobot(480, 360 * 2, true, true); + } + + @Override + protected void initUI() { + var frameSpinner = new Spinner(0, 23, 0); + frameSpinner.setPrefWidth(100); + + var btn = new Button("Play from frame"); + btn.setOnAction(e -> { + spawnRobotForFrame(900, 700, frameSpinner.getValue()); + }); + + var vbox = new VBox(10, frameSpinner, btn); + + addUINode(vbox, 1230, 820); + } + + private void spawnRobotForFrame(double x, double y, int startFrame) { + var animChannel = new AnimationChannel(image("robot_roll.png"), 7, 275, 275, Duration.seconds(2.6), 0, 23); + var animTexture = new AnimatedTexture(animChannel); + animTexture.playFrom(startFrame); + + var e = entityBuilder() + .at(x, y) + .view(animTexture) + .buildAndAttach(); + + animTexture.setOnCycleFinished(() -> e.removeFromWorld()); + } + + private void spawnRobot(double x, double y, Interpolator interpolator, String name) { + var text = addText(name, x + 120, y + 30); + text.fontProperty().unbind(); + text.setFont(Font.font(18)); + + var animChannel = new AnimationChannel(image("robot_roll.png"), 7, 275, 275, Duration.seconds(2.6), 0, 23); + var animTexture = new AnimatedTexture(animChannel); + animTexture.setInterpolator(interpolator); + animTexture.loop(); + + entityBuilder() + .at(x, y) + .view(animTexture) + .buildAndAttach(); + } + + private void spawnRobot(double x, double y, boolean isReverse, boolean isLoop) { + var text = addText(isReverse ? "Reverse" : "Play", x + 120, y + 30); + text.fontProperty().unbind(); + text.setFont(Font.font(18)); + + var animChannel = new AnimationChannel(image("robot_death.png"), 7, 275, 275, Duration.seconds(2.6), 0, 26); + var animTexture = new AnimatedTexture(animChannel); + + if (isLoop) { + if (isReverse) { + animTexture.loopReverse(); + } else { + animTexture.loop(); + } + } else { + if (isReverse) { + animTexture.playReverse(); + } else { + animTexture.play(); + } + } + + entityBuilder() + .at(x, y) + .view(animTexture) + .buildAndAttach(); + } + + public static void main(String[] args) { + launch(args); + } +}