当前位置: 首页 > 知识库问答 >
问题:

JavaFX时间轴动画性能不佳

刘胜泫
2023-03-14

我目前正在创建一个非常简单的JavaFX程序,模拟城市之间运送乘客的飞机和船只。到目前为止,我已经能够让飞机在几个城市进行短途飞行,但问题是,当我添加超过3或4架飞机时,动画速度非常慢。

我正在做的是使用Timeline类作为我的主游戏循环,清除并重新绘制画布上每帧60帧的平面图像。以下是时间表部分:

Timeline gameLoop = new Timeline();
gameLoop.setCycleCount( Timeline.INDEFINITE );

    KeyFrame keyFrame = new KeyFrame(
            Duration.seconds(0.017),
            new EventHandler<ActionEvent>()
            {
                public void handle(ActionEvent ae)
                {
                    dynamicGC.clearRect(0, 0, 1280, 800);

                    for (Plane plane : Spawner.planeList)
                    {
                        if(plane.isInFlight()) plane.Draw(dynamicGC);
                    }
                }
            });

gameLoop.getKeyFrames().add(keyFrame);
gameLoop.play();

以下是我如何为平面创建新线程:

//plane initalization
Thread t = new Thread(plane);
t.setDaemon(true);
t.start();

这是Plane类中定义的run()方法

public void run() {
    int routeCounter = 0;
    int direction = 1;
    boolean active = true;
    double recordedTime = 0.0;
    double aParameter = 0.0;
    while(active) {
        if (inFlight) {
            double tmpTime = System.currentTimeMillis();
            double timeDifference = tmpTime - recordedTime;
            recordedTime = tmpTime;

            double change = planeVelocity * (timeDifference) * direction;
            xCoordinate += change;
            yCoordinate += change * aParameter;
            if ( Math.abs(xCoordinate - Spawner.airportList.get(nextAirport).getXCoordinate()) < Spawner.airportList.get(nextAirport).getDetectionPrecision()
                    && Math.abs(yCoordinate - Spawner.airportList.get(nextAirport).getYCoordinate()) < Spawner.airportList.get(nextAirport).getDetectionPrecision()) {
                inFlight = false;
                routeCounter++;
            }
        } else {
            if(routeCounter < plannedRoute.size() ) {
                nextAirport = plannedRoute.get(routeCounter);
                aParameter = (Spawner.airportList.get(nextAirport).getYCoordinate() - this.yCoordinate)/
                        (Spawner.airportList.get(nextAirport).getXCoordinate() - this.xCoordinate);
                if (Spawner.airportList.get(nextAirport).getXCoordinate() < this.xCoordinate) {
                    direction = -1;
                } else direction = 1;
                recordedTime = System.currentTimeMillis();
                inFlight = true;
            }
            else active = false;
        }
    }

}

我知道代码非常混乱,但现在我想知道为什么动画速度会如此缓慢。我不确定我是否正确使用了线程。我还尝试了一些解决方案,比如在回答这个问题时缓存画布和组节点,但什么也没做。

编辑:似乎是线程减慢了程序的执行速度。

每次用JavaFX应用程序线程中的这个处理程序按下某个按钮时,我都会创建一个新平面(以及一个新线程):

@FXML
private void handleNewPassengerPlaneCreated(ActionEvent event) {
    ArrayList<Integer> route = new ArrayList<>();
    int startingAirport = Spawner.randomNumberGenerator.nextInt(Spawner.airportList.size());
    for(int i = 0; i < 3; i++) {
        int addedAirport = Spawner.randomNumberGenerator.nextInt(Spawner.airportList.size());
        if ( addedAirport != startingAirport)
            route.add(addedAirport);
    }

    System.out.println(Spawner.airportList.get(startingAirport).xCoordinate + " " + Spawner.airportList.get(startingAirport).yCoordinate );
    PassengerPlane plane = new PassengerPlane(Spawner.airportList.get(startingAirport).xCoordinate,
            Spawner.airportList.get(startingAirport).yCoordinate, "ID", 10, 1000, route, 300);
    Spawner.planeList.add(plane);
    new Thread(plane).start();
}

共有3个答案

陈宜修
2023-03-14

我想知道你为什么要用画布来达到这个目的。可能只是因为您已经习惯了AWT或类似的框架。场景图更适合这种问题。只需将场景图中的一些对象放置在它们的初始位置,然后在一个AnimationTimer中更新它们的位置和方向以及其他内容,就完成了。

穆子琪
2023-03-14

我有一个类似的问题,但是您可能需要考虑一些事情,它们可以极大地提高代码的性能

  • 对于每个需要动画的平面,创建一条路径,沿该路径为平面设置动画。看看如何沿贝塞尔曲线书写文本。然而,你的路径可能不是由一条Bèzier曲线构成的,更可能是一条Bèzier路径。请看以下文章:Bezier曲线教程和Bèzier路径算法,以及C#中的示例。然后,您只需为每个平面定义一个路径转换

从你的代码中我可以看到,你正在为每个平面创建一个单独的线程。线程是昂贵的对象,尤其是对于每次运行线程时只需要几个cpu周期的任务。然后,您必须考虑线程切换在实际计算时间内的成本。因此,在使用线程时,请确保将其用于长时间运行的任务。

宗乐池
2023-03-14

你应该使用不同的方法。看看“在JavaFX中,如何在屏幕上移动精灵?”中的答案。

你应该使用AnimationTimer来更新画布,而不是时间线。

关于您的问题:一个问题可能是您将线程与JavaFX线程混合在一起,这可能会导致问题,如果没有看到完整的代码,就无法判断。

 类似资料:
  • 我想知道为什么我的图表每次移动后屏幕都不清晰。这是我的代码: MainClass,我想删除其中的“时间”,并将其放在绘图方法updateScene中的lambda表达式中,但还不知道如何做到这一点:/ Axes类描述如何绘制轴: 缩放和绘制图表中我需要的一切。 绘图课负责制作动画,精确绘制我想要的图形。 屏幕显示我编译后得到的内容。就像我自上而下的问题一样,不知道是什么原因导致在每个时间线阶段后不

  • 我一直试图在我的UI中添加一个动画到我的气泡图中,但遇到了一些问题。我试图在不同的阶段增加气泡的大小,以显示渐变,但它只是画出它的全部大小,而不是在每个阶段。 体育推特计数是泡沫的最终值,我将其除以不同的数量,以显示最终值的建立。 有人有什么想法为什么这不像我期望的那样工作吗?

  • 在一个区域表面上有很多图像。我把它们分成小组。它们应该水平滚动成链。在这里输入图像描述 我写了一些方法来工作。例如。在左边切换位置。(rects-rectangles。早先是rectangles)。 例如。将元素从中心移到左边。 等等。

  • 我是JavaFX新手,我确信我在这里遗漏了一些明显的东西。我试图制作一个汽车的动画,它从左到右穿过一扇窗户,到达那里时绕着右边。用户应该能够点击up/down来调整动画的速度。当我使用一个对象时,动画开始运行,但发现你无法调整的,所以我在一个中重新编辑了它。 然而,随着时间的推移,我被卡住了。当我启动应用程序时,汽车不会显示在屏幕上。以下是我希望的一段简洁的代码片段: 还有消旋果烷: 编辑:根据@

  • 我想创建一个可滚动的时间线控制器,其中圆圈连接到填充有数字(圆的大小对应于包含数字)和尾随图标的基线。 因为我是JavaFX的新手,所以我不知道如何开始。在中,我将例如使用并使用其方法来绘制圆形、线条和图标... 在JavaFX中,我考虑过使用水平的和定制的,但我不确定它是否可以作为基线。所以我在寻找如何实现这种控制的想法。。。