0

画面上でボールをバウンドさせるプログラムを作成しました。以下に説明するプログラムは機能しません(ボールが画面から外れるだけです)。

ただし、whileループ内でブール変数atHorizo​​ntalEdgeとatVerticalEdgeを宣言すると、機能しているように見えます。なぜそうなのですか?ブール値はrun()メソッド全体に対して定義されているので、whileループの外側であっても、whileループで呼び出すことができるのではないでしょうか。

import acm.program.*;
import acm.graphics.*;
import java.awt.*;

public class BouncingBallv3 extends GraphicsProgram {
    public void run() {

        double x = (getWidth() - BALL_SIZE)/2 ;  //sets the starting position of ball at center
        double y = (getHeight() - BALL_SIZE)/2 ;


        GOval ball = new GOval (x, y, BALL_SIZE, BALL_SIZE ); // creates a red ball at center of screen
        ball.setFilled(true);
        ball.setColor(Color.red);
        add (ball);

        double dx = 1; //increments by which the ball moves
        double dy = 1;

        //declares boolean variables to test if ball position is at an edge
        boolean atHorizontalEdge =  (ball.getX() == getWidth() - BALL_SIZE) || ball.getX() == 0 ; 
        boolean atVerticalEdge = (ball.getY() == getHeight() - BALL_SIZE) || ball.getY() == 0 ;

        /* while loop keeps the ball moving in direction dx,dy
         * if ball reaches a position at any edge, the direction dx or dy changes
         */

        while (true) {

            if (atHorizontalEdge) {          //changes direction of ball if it hits a left/right wall
                dx = -dx;
            } else if (atVerticalEdge) {     //changes direction of ball if it hits a top/bottom wall
                dy = -dy;
            }
                ball.move(dx,dy); 
                pause (PAUSE_TIME);

        }



    }



    private static final double BALL_SIZE = 50;
    private static final int PAUSE_TIME = 5;
}
4

3 に答える 3

4

問題は、ブール値の宣言がwhileループの外側にあるということではありません。これは、whileループの外側で境界をチェックしているということです。このため、状態が更新されることはなく、ボールの元の状態のみがチェックされます。

于 2011-11-06T06:39:43.433 に答える
0

atHorizontalEdge反復するたびに、ループ本体のとを更新する必要があるatVerticalEdgeと思います。


アップデート:

whileループの本体は次のようになります。`//ブール変数を宣言して、ボールの位置がエッジにあるかどうかをテストします。ブールatHorizo​​ntalEdge = false; boolean atVerticalEdge = false;

    /* while loop keeps the ball moving in direction dx,dy
     * if ball reaches a position at any edge, the direction dx or dy changes
     */

    while (true) {
        atHorizontalEdge = (ball.getX() == getWidth() - BALL_SIZE) || ball.getX() == 0;
        atVerticalEdge = (ball.getY() == getHeight() - BALL_SIZE) || ball.getY() == 0;

        if (atHorizontalEdge) {          //changes direction of ball if it hits a left/right wall
            dx = -dx;
        } else if (atVerticalEdge) {     //changes direction of ball if it hits a top/bottom wall
            dy = -dy;
        }
            ball.move(dx,dy); 
            pause (PAUSE_TIME);

    }`

atHorizontalEdgeループ内で定義した場合に機能する理由atVerticalEdgeは、反復ごとにこれら2つの変数が再計算される(つまり更新される)ためです。

于 2011-11-06T06:41:07.740 に答える
0

atHorizontalEdgeループの内側または外側で宣言できますが、これは重要ではありませんatVerticalEdgewhile

重要なことは、ループが開始する前に、以下が1回だけ計算されることです。

atHorizontalEdge =  (ball.getX() == getWidth() - BALL_SIZE) || ball.getX() == 0 ; 
atVerticalEdge = (ball.getY() == getHeight() - BALL_SIZE) || ball.getY() == 0 ;

したがってatHorizontalEdge、メソッドatVerticalEdgeの最初から最後までrun(これは永久に)同じ値になります。

上記の2行は、それ自体では更新されないため、ループ内のすべての反復で実行する必要があることは明らかです...

while (true) {
   atHorizontalEdge =  (ball.getX() == getWidth() - BALL_SIZE) || ball.getX() == 0 ; 
   atVerticalEdge = (ball.getY() == getHeight() - BALL_SIZE) || ball.getY() == 0 ;
   ...
}


編集:また、 2つの理由から、xとyが幅/高さ以上であり、0以下であるどうかを確認することをお勧めします。

  1. 増分を1から変更する場合は、その正確な値をスキップしてバグを引き起こす可能性がありますが、さらに重要なのは次のとおりです。
  2. を使用しているdoubleと、数値の浮動小数点表現が比較対象と正確に一致==しない可能性があるため、バグが発生する可能性があり、ボールがエッジを超えて進み続ける可能性があります。

すなわち。ball.getX() >= getWidth() ... ball.getX() <= 0

すべてのコンピューター科学者が浮動小数点演算について知っておくべきこと

于 2011-11-06T06:49:53.700 に答える