【问题标题】:JavaFX SequentialTransition IllegalStateException: Cannot stop when embedded in another animationJavaFX SequentialTransition IllegalStateException:嵌入另一个动画时无法停止
【发布时间】:2020-11-21 05:59:38
【问题描述】:

下面的测试程序重现了这个问题。我理解抛出异常的原因,但我想知道如何解决它或在 JavaFX 中使用不同的构造来获得我想要的。

完整的应用程序是一个机器人模拟器,其中包含多个机器人,这些机器人可以自主、独立并同时在一个场地周围移动。每个机器人都有自己的 SequentialTransition 用于其特定的一组动作。该程序将 SequentialTransitions 添加到 ParallelTransition,然后播放。一切都很好,直到我设置了一个监听器,它会注意到机器人是否遇到了障碍物。我已将测试程序中的碰撞检测简化为仅适用于一个机器人和一堵墙。错误点标有 //** BROKEN!!下一行出现 IllegalStateException。

我真的想为遇到障碍物的机器人停止 SequentialTransition,但让其他机器人继续。我该怎么做?

该错误出现在 Java 8 中,但也出现在 Java 11 和 JavaFX 15 中。

package sample;

import javafx.animation.ParallelTransition;
import javafx.animation.SequentialTransition;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Main extends Application {

    private static final double FIELD_WIDTH = 600;
    private static final double FIELD_HEIGHT = 600;

    private Pane field = new Pane();
    ParallelTransition parallel = new ParallelTransition();
    SequentialTransition sequentialRobot1 = new SequentialTransition();
    SequentialTransition sequentialRobot2 = new SequentialTransition();

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));

        // Place one field boundary for testing.
        Line northBoundary = new Line(0, 0, FIELD_WIDTH, 0);
        northBoundary.setStrokeWidth(5.0);
        field.getChildren().add(northBoundary);

        // Place the robots on the field.
        // The first robot.
        Rectangle robotBody1 = new Rectangle(100, 300, 60, 60);
        robotBody1.setArcHeight(15);
        robotBody1.setArcWidth(15);
        robotBody1.setStroke(Color.BLACK);
        robotBody1.setFill(Color.CRIMSON);
        field.getChildren().add(robotBody1);

        robotBody1.boundsInParentProperty().addListener((observable, oldValue, newValue) -> {
            if (northBoundary.getBoundsInParent().intersects(robotBody1.getBoundsInParent())) {
                //** BROKEN!! IllegalStateException on next line
                sequentialRobot1.stop();
                System.out.println("Collision detected");
                parallel.play();
            }
        });

        TranslateTransition translateTransition1 = new TranslateTransition();
        translateTransition1.setNode(robotBody1);
        translateTransition1.setByX(0);
        translateTransition1.setByY(-300);
        translateTransition1.setDuration(Duration.seconds(1));
        translateTransition1.setOnFinished(event -> {
            robotBody1.setLayoutX(robotBody1.getLayoutX() + robotBody1.getTranslateX());
            robotBody1.setLayoutY(robotBody1.getLayoutY() + robotBody1.getTranslateY());
            robotBody1.setTranslateX(0);
            robotBody1.setTranslateY(0);
        });
        sequentialRobot1.getChildren().add(translateTransition1);

        // The second robot.
        Rectangle robotBody2 = new Rectangle(300, 300, 60, 60);
        robotBody2.setArcHeight(15);
        robotBody2.setArcWidth(15);
        robotBody2.setStroke(Color.BLACK);
        robotBody2.setFill(Color.CYAN);
        field.getChildren().add(robotBody2);

        TranslateTransition translateTransition2 = new TranslateTransition();
        translateTransition2.setNode(robotBody2);
        translateTransition2.setByX(0);
        translateTransition2.setByY(-100);
        translateTransition2.setDuration(Duration.seconds(1));
        translateTransition2.setOnFinished(event -> {
            robotBody2.setLayoutX(robotBody2.getLayoutX() + robotBody2.getTranslateX());
            robotBody2.setLayoutY(robotBody2.getLayoutY() + robotBody2.getTranslateY());
            robotBody2.setTranslateX(0);
            robotBody2.setTranslateY(0);
        });
        sequentialRobot2.getChildren().add(translateTransition2);

        parallel.getChildren().addAll(sequentialRobot1, sequentialRobot2);
        parallel.play();

        primaryStage.setTitle("Field");
        primaryStage.setScene(new Scene(field, FIELD_WIDTH, FIELD_HEIGHT, Color.GRAY));
        primaryStage.show();
    }


    public static void main(String[] args) {
        launch(args);
    }
}

【问题讨论】:

  • 您似乎对如何实现您想要做的事情感到困惑。 TransitionsSequentialsParallel 的工作方式似乎不合逻辑。
  • 使用单个AnimationTimer 来更新每个机器人每次调用的位置可能更有意义。如果机器人遇到障碍物,请不要移动该机器人。
  • 要使您的代码minimal reproducible example 添加fxml 文件或更好地以编程方式定义root

标签: javafx


【解决方案1】:

@Slaw 使用 AnimationTimer 的想法可能是最好的方向,但显而易见的答案是根本不使用 ParallelTransition。由于机器人动画将是独立的,只需使用 SequentialTransitions 并通过在每个上调用 play() 来同时启动它们。

【讨论】:

  • 我按照你的建议做了,测试程序按我的意愿执行。我想我需要阅读更多关于 ParallelTransitiion 的最佳使用的信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-18
  • 2017-05-15
  • 2011-03-06
  • 1970-01-01
  • 2018-02-12
相关资源
最近更新 更多