2017-09-24 13 views
0

スレッドを使用して移動するバウンスボールを作成し、上下の矢印キーを使用して速度を変更することができます。移動円がランダムに消えます(javafx)

私はボールとは別にいくつかの種類のいくつかの目に見えない四角形の後ろに無作為に消えるボールから離れて動作します。ラベルを削除すると、これはもう発生しないため、左上の速度ラベルに関連している可能性があります。問題の

のGIF:

Controlクラス:

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

答えて

2

この問題はxの不適切な更新によって引き起こされているように見えますおよびyプロパティCircle

コードでは、Circleの位置の変更がレンダリングスレッドに表示され、speedフィールドの変更がアニメーションスレッドから見えることをJVMが保証する必要はありません。

BTW:アニメーションスレッドをデーモンスレッドとしてマークしないので、JVMのシャットダウンを防ぐことができます。デーモンとして

設定スレッド:しかし、この目的のために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); 
    }); 
} 

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

適切な更新がはるかに簡単になります:

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

関連する問題