логический флаг не читается во время цикла (Java) - PullRequest
0 голосов
/ 06 ноября 2011

Я написал программу для отскока мяча вокруг экрана.Программа, как написано ниже, не работает (шарик просто движется за пределы экрана).

Однако, если я объявлю логические переменные atHorizontEdge и atVerticalEdge внутри цикла while, похоже, что он будет работать.Почему это так?Поскольку логические значения определены для всего метода 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;
}

Ответы [ 3 ]

4 голосов
/ 06 ноября 2011

Проблема не в том, что объявление логических значений находится вне цикла while. Это то, что вы проверяете свои границы вне цикла while. Из-за этого ваше состояние никогда не обновляется, а проверяется только исходное состояние мяча.

0 голосов
/ 06 ноября 2011

atHorizontalEdge и atVerticalEdge могут быть объявлены внутри или вне цикла while, это не важно.

Важно то, что следующее вычисляется только один раз ,перед началом цикла:

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

Поэтому каждый из atHorizontalEdge и atVerticalEdge будет иметь одинаковое значение от начала до конца вашего run метода (который навсегда).

Вы, очевидно, хотите, чтобы две вышеупомянутые строки выполнялись на каждой итерации в вашем цикле, поскольку они не собираются обновляться сами по себе ...

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

РЕДАКТИРОВАТЬ: Кроме того, было бы лучше проверить, если x и y были больше или равны ширина / высота, и меньше или равно 0 по двум причинам:

  1. Если вы решите изменить приращение с 1, вы можете пропустить это точное значение и вызвать ошибку, но что более важно:
  2. Вы используете double, и представление числа с плавающей точкой может не быть точно с чем вы сравниваете его, так что == может вызвать ошибки, и шар можетПройдите край и продолжайте идти.

т.е.ball.getX() >= getWidth() ... ball.getX() <= 0

Что должен знать каждый компьютерщик об арифметике с плавающей точкой

0 голосов
/ 06 ноября 2011

Вы должны обновлять atHorizontalEdge и atVerticalEdge в теле цикла после каждой итерации, я думаю.


UPDATE:

Тело цикла while должно быть таким, ` // объявляем логические переменные, чтобы проверить, находится ли позиция шара на краю логическое значение atHorizontEdge = false; логическое значение 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 внутри цикла, состоит в том, что на каждой итерации эти две переменные пересчитываются (то есть обновляются).

...