在JavaFX中使用AnimationTimer移动圆时如何防止滞后?

问题描述 投票:0回答:1

我对 AnimationTimer 类有问题,我用它来移动圆(球)。 当我运行程序(是乒乓球游戏)时,球停止了一会儿(0.5-1秒),然后继续运动(球运动如此滞后)

这是主控制器类

package com.anas.pong;

import javafx.animation.AnimationTimer;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;

import java.net.URL;
import java.util.ResourceBundle;

public class MainController implements Initializable {
    private enum MoveTo {
        bottomLeft,
        topLeft,
        topRight,
        bottomRight
    }
    private MoveTo where;
    private Circle ball;
    int ballX, ballY;


    @FXML
    private AnchorPane mainPane;

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {

        // setting the ball
        ball = new Circle();
        ball.setRadius(13);
        ball.setStroke(Color.BLACK);
        ball.setFill(Color.BLACK);

        // setting position of the ball
        ball.setLayoutX(400);
        ballX = 400;
        ball.setLayoutY(300);
        ballY = 300;

        mainPane.getChildren().add(ball);

        where = MoveTo.bottomLeft;

        AnimationTimer movement = new AnimationTimer() {
            @Override
            public void handle(long l) {
                // moving to ...
                if (where.equals(MoveTo.bottomLeft))
                    bottomLeftMovement();
                else if (where.equals(MoveTo.topLeft))
                    topLeftMovement();
                else if (where.equals(MoveTo.topRight))
                    topRightMovement();
                else if (where.equals(MoveTo.bottomRight))
                    bottomRightMovement();
                else {
                    System.out.println("Nothing");
                    stop();
                }
            }
        };

        movement.start();
    }

    private void bottomLeftMovement() {

        // go bottom
        ball.setTranslateY(ball.getTranslateY()+2);
        ballY += 2;

        // go left
        ball.setTranslateX(ball.getTranslateX()-2);
        ballX -= 2;

        if (ballY >= 600-13)
            where = MoveTo.topLeft;

        else if (ballX <= 13) // 0+13
            where = MoveTo.bottomRight;

    }

    private void topLeftMovement() {
        ball.setTranslateY(ball.getTranslateY()-2);
        ballY -= 2;

        ball.setTranslateX(ball.getTranslateX()-2);
        ballX -= 2;

        if (ballX <= 13) // 0+13
            where = MoveTo.topRight;

        else if (ballY <= 13) // 0+13
            where = MoveTo.bottomLeft;

    }

    private void topRightMovement() {
        ball.setTranslateY(ball.getTranslateY()-2);
        ballY -= 2;

        ball.setTranslateX(ball.getTranslateX()+2);
        ballX += 2;

        if (ballX >= 800-13)
            where = MoveTo.topLeft;

        else if (ballY <= 13)
            where = MoveTo.bottomRight;

    }

    private void bottomRightMovement() {
        ball.setTranslateY(ball.getTranslateY()+2);
        ballY += 2;

        ball.setTranslateX(ball.getTranslateX()+2);
        ballX += 2;

        if (ballY >= 600-13)
            where = MoveTo.topRight;

        else if (ballX >= 800-13)
            where = MoveTo.bottomLeft;

    }
}

球应该停留在(800,600)的窗口中并且可以工作,但有时球会停止(0.5-1秒),我认为问题来自AnimationTimer类,但我尝试过TranslateTransition和Thread(with while(true))他们都有同样的问题(运动滞后)。

java animation javafx transition
1个回答
0
投票

OP 代码使一切变得比必要的复杂得多。 设置为在其

PauseTransition
中自行播放的
onFinished Property
将处理循环动画。

使用

Node.layoutX
Node.layoutY
也可能比使用
Node.translateX
Node.translateY
更干净,尽管当
Node
留在 [0,0] 然后翻译时不会有太大区别。

如果方向枚举也有要应用的 x 和 y 增量的字段,它会更有用,但实际上完全没有必要。 球将始终具有 X 和 Y 增量(在本例中均为 +- 2.0),并且当到达墙壁时它们会简单地反转。 无论 X 和 Y 增量的当前值是多少,墙壁碰撞的逻辑都是相同的。

当布局基本上不存在时,FXML 或

AnchorPane
就没用了。 因此,一个简单的
Pane
就可以正常工作,并且
Circle
只是添加到代码中,就像在 OP 中一样。

这是 Kotlin 中的版本(所有 JavaFX 想法在 Kotlin 中都是相同的):

class Pong : Application() {
    override fun start(stage: Stage) {
        stage.scene = Scene(createContent(), 800.0, 600.0)
        stage.show()
    }

    private fun createContent() = Pane().apply {
        val ballX: DoubleProperty = SimpleDoubleProperty(400.0)
        val ballY: DoubleProperty = SimpleDoubleProperty(300.0)
        var moveX = -2.0
        var moveY = -2.0
        val ball = Circle(13.0).apply {
            layoutXProperty().bind(ballX)
            layoutYProperty().bind(ballY)
        }
        children += ball
        val animation = PauseTransition(Duration.millis(10.0)).apply {
            setOnFinished {
                ballX.value += moveX
                ballY.value += moveY
                if ((ballX.doubleValue() > (800 - 13) || (ballX.doubleValue() < 13))) {
                    moveX *= (-1)
                }
                if ((ballY.doubleValue() > (600 - 13) || (ballY.doubleValue() < 13))) {
                    moveY *= (-1)
                }
                playFromStart()
            }
        }
        animation.play()
    }
}

fun main() = Application.launch(Pong::class.java)

它会运行,球会在

Pane
周围愉快地弹跳,没有任何犹豫或抖动。

© www.soinside.com 2019 - 2024. All rights reserved.