移动圈随机消失(javafx) [英] Moving circle randomly disappears (javafx)

查看:201
本文介绍了移动圈随机消失(javafx)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

uni的分配 - 必须制作一个使用线程移动的弹跳球,你可以使用向上和向下箭头键改变速度。

Assignment for uni - have to make a bouncing ball that is moved using a thread and you can change the speed using the up and down arrow keys.

我是什么除了球在一些看不见的方格后随机消失之外,它们的工作正常。它可能与左上角的速度标签有关,因为当我删除标签时,这不再发生。

What I have works fine apart from the ball randomly disappearing behind some invisible squares of some kind. It may be related to the speed label in the top left because when I remove the label, this doesn't happen anymore.

问题的Gif:

对照类:

public class Task3Control extends Application {

    public void start(Stage stagePrimary) {

        //create the ball
        Task3Ball ball = new Task3Ball();

        //create a label to show to ball's current speed
        Label labelSpeed = new Label("Ball Speed: "+ball.getSpeed());

        //create the root pane and place the ball and label within it
        Pane paneRoot = new Pane();
        paneRoot.getChildren().addAll(labelSpeed, ball.circle);

        //create a thread to animate the ball and start it
        Thread t = new Thread(ball);
        t.start();

        //increase and decrease the speed of the ball when the up and down arrow keys are pressed
        //also update the label to reflect the new speed
        paneRoot.setOnKeyPressed(e -> {
            if (e.getCode() == KeyCode.UP) {
                ball.increaseSpeed();
                labelSpeed.setText("Ball Speed: "+ball.getSpeed());
            } 
            else if (e.getCode() == KeyCode.DOWN) {
                ball.decreaseSpeed();
                labelSpeed.setText("Ball Speed: "+ball.getSpeed());
            }
        });

        //Create a scene containing the root pane and place it in the primary stage
        //Set the title of the window to 'Bouncing Ball Animation'
        Scene scene = new Scene(paneRoot, 400, 300);
        stagePrimary.setTitle("Bouncing Ball Animation");
        stagePrimary.setScene(scene);
        stagePrimary.show();
        paneRoot.requestFocus();
    }

球类:

public class Task3Ball implements Runnable {

    private double radius = 20;
    private double x = radius*2, y = radius*2;
    private double dx = 1, dy = 1;
    private double speed = 3.0;
    public Circle circle = new Circle(radius,Color.GREEN);

    /** Returns the current speed of the ball.
     * @return (String) the speed as a string, formatted to two decimal places
     */
    public String getSpeed() {
        return String.format("%.2f", speed);
    }

    /** Increases the speed of the ball by 0.1 to a maximum of 5.
     */
    public void increaseSpeed() {
        speed += 0.1;
        if (speed > 5)
            speed = 5;
    }

    /** Decreases the speed of the ball by 0.1 to a minimum of 1.
     */
    public void decreaseSpeed() {
        speed -= 0.1;
        if (speed < 1)
            speed = 1;
    }

    /** Moves the ball based on its current speed and direction.
     * Reverses the direction of the ball when it collides with the edge of the window.
     * Updates the circle object to reflect its current position.
     */
    protected void moveBall() {

        if (x-radius <= 0 || x+radius >= 400)
            dx *= -1;

        if (y-radius <= 0 || y+radius >= 300)
            dy *= -1;

        x += dx*speed;
        y += dy*speed;
        circle.setCenterX(x);
        circle.setCenterY(y);
    }

    /** Uses a thread to move the ball every 20 milliseconds.
     */
    public void run() {

        while(true) {
            try {
                moveBall();
                Thread.sleep(20);
            }
            catch(InterruptedException e) {
                System.out.println("interrupt");
            }
        }
    }
}


推荐答案

此问题似乎是由于 x y 属性的不正确更新造成的 Circle

This issue seems to be caused by improper updating of the x and y properties of the Circle.

请注意,鉴于您的代码,JVM无需保证对其进行任何修改 Circle 的位置对于呈现线程是可见的,并且 speed 字段的任何修改都对动画线程可见。

Note that given your code the JVM doesn't need to guarantee that any modifications of the position of the Circle are visible to the rendering thread and that any modifications of the speed field are visible to the animation thread.

BTW:你没有将动画线程标记为守护程序线程,因此它会阻止JVM关闭。

BTW: You do not mark the animation thread as daemon thread so it will prevent the JVM from shutting down.

将线程设置为守护程序:

Thread t = new Thread(ball);
t.setDaemon(true);
t.start();

正确更新圈子位置

// variable never updated so there are no issues with synchronisation
private final double radius = 20;

...

protected void moveBall() {
    // do updates on the JavaFX application thread
    Platform.runLater(() -> {
        if (x - radius <= 0 || x + radius >= 400) {
            dx *= -1;
        }

        if (y - radius <= 0 || y + radius >= 300) {
            dy *= -1;
        }

        x += dx * speed;
        y += dy * speed;
        circle.setCenterX(x);
        circle.setCenterY(y);
    });
}






但是使用时间线为此目的会简单得多:


However using a Timeline for this purpose would be much simpler:

public class Task3Ball {

    private Timeline timeline;

    ...

    protected void moveBall() {
        if (x - radius <= 0 || x + radius >= 400) {
            dx *= -1;
        }

        if (y - radius <= 0 || y + radius >= 300) {
            dy *= -1;
        }

        x += dx * speed;
        y += dy * speed;
        circle.setCenterX(x);
        circle.setCenterY(y);
    }

    public void startAnimation() {
        if (timeline == null) {
            // lazily create timeline
            timeline = new Timeline(new KeyFrame(Duration.millis(20), event -> moveBall()));
            timeline.setCycleCount(Animation.INDEFINITE);
        }

        // ensure the animation is playing
        timeline.play();
    }
}





//Thread t = new Thread(ball);
//t.start();
ball.startAnimation();

这篇关于移动圈随机消失(javafx)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆