2017-09-24 121 views
0

uni的分配 - 必須製作使用線程移動的彈跳球,並且您可以使用向上和向下箭頭鍵更改速度。動圈隨機消失(javafx)

除了球隨機消失在某種看不見的方塊之外,我的工作很好。它可能與左上方的速度標籤有關,因爲當我移除標籤時,這種情況不再發生。

的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(); 
    } 

Ball類:

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"); 
      } 
     } 
    } 
} 

回答

2

這個問題似乎是由x的更新不當引起和y properti es的Circle

請注意,在您的代碼中,JVM不需要保證Circle的位置的任何修改對渲染線程可見,並且speed字段的任何修改對於動畫線程都是可見的。

順便說一句:你不會將動畫線程標記爲守護線程,所以它會阻止JVM關閉。

設置線程作爲守護程序:

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

但是使用用於此目的的Timeline圓圈位置

// 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); 
    }); 
} 

進行適當更新就會簡單得多:

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(); 
+0

完美。非常感謝Fabian! :) – somebloke