Java 中的打砖块游戏在调用remove() 方法后不传递布尔值

发布于 2024-10-31 16:05:20 字数 7313 浏览 3 评论 0原文

我一直在网上听CS106A的讲座并做作业。我在突破游戏上被困了几天,因为我无法理解它的行为。

基本上,我已经构建了环境,砖块,球,桨,边缘,我可以让球在环境中弹跳。我什至可以让球从砖块上弹开,甚至可以移走砖块。但我无法让球从砖块上弹起并同时移走砖块。

如果您查看我的代码,您会发现我有一个反转球方向的方法。此方法从我的方法中获取一个布尔值,用于检查球是否与环境中的任何对象发生碰撞。如果我不包含“remove()”方法,球将按预期从砖块上弹开。如果我确实包含该方法,球将移走砖块,但不会从它们上反弹。这向我表明代码正在被读取并返回布尔值,但该值没有改变球移动的方向。

/*
 * File: Breakout.java
 * -------------------
 * Name:
 * Section Leader:
 * 
 * This file will eventually implement the game of Breakout.
 */

import java.awt.Color;
import java.awt.event.MouseEvent;

import acm.graphics.GArc;
import acm.graphics.GLine;
import acm.graphics.GObject;
import acm.graphics.GOval;
import acm.graphics.GRect;
import acm.program.GraphicsProgram;
import acm.util.RandomGenerator;


public class Breakout extends GraphicsProgram {

/** Width and height of application window in pixels */
    public static final int APPLICATION_WIDTH = 400;
    public static final int APPLICATION_HEIGHT = 600;

/** Dimensions of game board (usually the same) */
    private static final int WIDTH = APPLICATION_WIDTH;
    private static final int HEIGHT = APPLICATION_HEIGHT;

/** Dimensions of the paddle */
    private static final int PADDLE_WIDTH = 60;
    private static final int PADDLE_HEIGHT = 10;

/** Offset of the paddle up from the bottom */
    private static final int PADDLE_Y_OFFSET = 30;

/** Number of bricks per row */
    private static final int NBRICKS_PER_ROW = 10;

/** Number of rows of bricks */
    private static final int NBRICK_ROWS = 10;

/** Separation between bricks */
    private static final int BRICK_SEP = 4;

/** Width of a brick */
    private static final int BRICK_WIDTH =
      (WIDTH - (NBRICKS_PER_ROW - 1) * BRICK_SEP) / NBRICKS_PER_ROW;

/** Height of a brick */
    private static final int BRICK_HEIGHT = 8;

/** Radius of the ball in pixels */
    private static final int BALL_RADIUS = 10;

/** Offset of the top brick row from the top */
    private static final int BRICK_Y_OFFSET = 70;

/** Number of turns */
/** private static final int NTURNS = 3;*/

/* Method: run() */
/** Runs the Breakout program. */

    public void run() {
        init();
        createBall();
        createSides();
        createBlocks();
        createPaddle();
        addMouseListeners();
        waitForClick();
        while (BALL.getY() <= HEIGHT){
            play();
        }
    }

    public void init(){
        setSize(500,700);
    }

    private void createBlocks(){
        int BRICKS = 0;
        int ROWS = 0;
        while (ROWS != NBRICK_ROWS) {
            while (BRICKS != NBRICKS_PER_ROW){
                GRect BRICK = new GRect (BRICK_WIDTH, BRICK_HEIGHT);
                BRICK.setLocation((BRICKS*(BRICK_SEP + BRICK_WIDTH)+BRICK_SEP), BRICK_Y_OFFSET + (ROWS*(BRICK_HEIGHT + BRICK_SEP)));
                BRICK.setFilled(true);
                if (ROWS == 0 || ROWS == 1){
                    BRICK.setColor(Color.RED);
                    BRICK.setFilled(true);}
                    else if (ROWS == 2 || ROWS == 3) {
                        BRICK.setColor(Color.ORANGE);
                    }   
                    else if (ROWS == 4 || ROWS == 5){
                        BRICK.setColor(Color.YELLOW);
                    }
                    else if (ROWS == 6 || ROWS == 7){
                        BRICK.setColor(Color.GREEN);
                    }
                    else if (ROWS == 8 || ROWS == 9){
                        BRICK.setColor(Color.CYAN);
                    }
                add(BRICK);
                BRICKS++;
            }
            ROWS++;
            BRICKS = 0;
        }
    }

    private void createSides(){
        add(rightSide);
        add(leftSide);
        add(topSide);
        add(bottomSide);
    }

    private void createPaddle(){
        PADDLE.setFilled(true);
        add(PADDLE, WIDTH/2 - (PADDLE_WIDTH/2), HEIGHT - PADDLE_Y_OFFSET);
    }

    private void createBall(){
        BALL.setFilled(true);
        BALL.setLocation(WIDTH/2 - 18, HEIGHT/2);
        add(BALL);
    }

    private void play(){
        /* Add Title Text or Lives or Score */
        ballMovement();
    }

    private void ballMovement(){
        BRICK_COUNT = (NBRICKS_PER_ROW*NBRICK_ROWS);
        while (BRICK_COUNT != 0){
            BALL.move(ballXVelocity(), ballYVelocity());
            pause(5);
            checkXCollision();
            checkYCollision();
        }
    }

    public int ballXVelocity(){
        boolean x = checkXCollision();
        if (x == true){
            BALL_X_VELOCITY = -INITIAL_X_VELOCITY;
            INITIAL_X_VELOCITY = BALL_X_VELOCITY;
        }
        else {BALL_X_VELOCITY = INITIAL_X_VELOCITY;}
        return BALL_X_VELOCITY;
    }

    public int ballYVelocity(){
        boolean y = checkYCollision();
        if (y == true){
            BALL_Y_VELOCITY = -INITIAL_Y_VELOCITY;
            INITIAL_Y_VELOCITY = BALL_Y_VELOCITY;
        }
        else {BALL_Y_VELOCITY = INITIAL_Y_VELOCITY;}
        return BALL_Y_VELOCITY;
    }

    private boolean checkXCollision(){
        double ballX = BALL.getX();
        double ballY = BALL.getY();
        GObject colObjLeft = getElementAt(ballX, ballY - BALL_RADIUS);
        GObject colObjRight = getElementAt(ballX + BALL_RADIUS*2, ballY- BALL_RADIUS);
        if (ballX <= 0 || ballX + (BALL_RADIUS*2) >= APPLICATION_WIDTH){
            return true;
        }
        else if (colObjLeft != null){

            return true;
        }
        else if (colObjRight != null){

            return true;
        }
        else {return false;}
    }

    private boolean checkYCollision(){
        double ballX = BALL.getX();
        double ballY = BALL.getY();
        GObject colObjTop = getElementAt(ballX+ BALL_RADIUS, ballY - 1);
        GObject colObjBot = getElementAt(ballX + BALL_RADIUS, ballY + (BALL_RADIUS*2) + 1);
        if(colObjBot == PADDLE){
            return true;
        } 
        else if (ballY <= 0){
            return true;
            }
        else if (colObjTop != null && colObjTop != BALL){
            remove(colObjTop);
            return true;
        }   
        else if (colObjBot != null && colObjBot != PADDLE && colObjBot != BALL){
            remove(colObjBot);
            return true;
        }
        else {return false;}
    }

    public void mouseMoved(MouseEvent e){
        if (e != null){     
            int x = e.getX();
            PADDLE.setLocation(x - (PADDLE_WIDTH/2), HEIGHT - PADDLE_Y_OFFSET);
        }
    }

    /*public void paddleLocation(dx,dy);*/
        /*int x = */

    public GRect PADDLE = new GRect(PADDLE_WIDTH, PADDLE_HEIGHT);
    private GArc BALL = new GArc(BALL_RADIUS*2, BALL_RADIUS*2, 0,360);
    /*private GOval BALL = new GOval(BALL_RADIUS*2, BALL_RADIUS*2);*/
    private int BRICK_COUNT;
    private int BALL_Y_VELOCITY;
    private int BALL_X_VELOCITY;
    private int INITIAL_Y_VELOCITY = 1;
    private RandomGenerator rgen = RandomGenerator.getInstance();
    private int INITIAL_X_VELOCITY = rgen.nextInt(2);
    private GLine rightSide = new GLine (WIDTH, 0, WIDTH, HEIGHT );
    private GLine leftSide = new GLine (0, 0, 0, HEIGHT);
    private GLine topSide = new GLine (0, 0, WIDTH, 0);
    private GLine bottomSide = new GLine (0, HEIGHT, WIDTH, HEIGHT);
}

I have been following the CS106A lectures online and doing the assignments. I've been stuck for a few days though on the breakout game because I cannot understand it's behavior.

Basically, I have built the environment, bricks, ball, paddle, edges, and I can get the ball to bounce around in the environment. I can get the ball to even bounce off the bricks and I can even remove the bricks. But I cannot get the ball to bounce off the bricks and remove the bricks at the same time.

If you look in my code, you will see that I have a method for reversing the direction of the ball. This method takes a boolean value from my method that checks if the ball has collided with any of the objects in the environment. If I do not include the method 'remove()' the ball will bounce off the bricks as expected. If I do include that method, the ball will remove the bricks but not bounce off of them. This indicates to me that the code is being read and returning the boolean value but the value is not changing the direction the ball is moving.

/*
 * File: Breakout.java
 * -------------------
 * Name:
 * Section Leader:
 * 
 * This file will eventually implement the game of Breakout.
 */

import java.awt.Color;
import java.awt.event.MouseEvent;

import acm.graphics.GArc;
import acm.graphics.GLine;
import acm.graphics.GObject;
import acm.graphics.GOval;
import acm.graphics.GRect;
import acm.program.GraphicsProgram;
import acm.util.RandomGenerator;


public class Breakout extends GraphicsProgram {

/** Width and height of application window in pixels */
    public static final int APPLICATION_WIDTH = 400;
    public static final int APPLICATION_HEIGHT = 600;

/** Dimensions of game board (usually the same) */
    private static final int WIDTH = APPLICATION_WIDTH;
    private static final int HEIGHT = APPLICATION_HEIGHT;

/** Dimensions of the paddle */
    private static final int PADDLE_WIDTH = 60;
    private static final int PADDLE_HEIGHT = 10;

/** Offset of the paddle up from the bottom */
    private static final int PADDLE_Y_OFFSET = 30;

/** Number of bricks per row */
    private static final int NBRICKS_PER_ROW = 10;

/** Number of rows of bricks */
    private static final int NBRICK_ROWS = 10;

/** Separation between bricks */
    private static final int BRICK_SEP = 4;

/** Width of a brick */
    private static final int BRICK_WIDTH =
      (WIDTH - (NBRICKS_PER_ROW - 1) * BRICK_SEP) / NBRICKS_PER_ROW;

/** Height of a brick */
    private static final int BRICK_HEIGHT = 8;

/** Radius of the ball in pixels */
    private static final int BALL_RADIUS = 10;

/** Offset of the top brick row from the top */
    private static final int BRICK_Y_OFFSET = 70;

/** Number of turns */
/** private static final int NTURNS = 3;*/

/* Method: run() */
/** Runs the Breakout program. */

    public void run() {
        init();
        createBall();
        createSides();
        createBlocks();
        createPaddle();
        addMouseListeners();
        waitForClick();
        while (BALL.getY() <= HEIGHT){
            play();
        }
    }

    public void init(){
        setSize(500,700);
    }

    private void createBlocks(){
        int BRICKS = 0;
        int ROWS = 0;
        while (ROWS != NBRICK_ROWS) {
            while (BRICKS != NBRICKS_PER_ROW){
                GRect BRICK = new GRect (BRICK_WIDTH, BRICK_HEIGHT);
                BRICK.setLocation((BRICKS*(BRICK_SEP + BRICK_WIDTH)+BRICK_SEP), BRICK_Y_OFFSET + (ROWS*(BRICK_HEIGHT + BRICK_SEP)));
                BRICK.setFilled(true);
                if (ROWS == 0 || ROWS == 1){
                    BRICK.setColor(Color.RED);
                    BRICK.setFilled(true);}
                    else if (ROWS == 2 || ROWS == 3) {
                        BRICK.setColor(Color.ORANGE);
                    }   
                    else if (ROWS == 4 || ROWS == 5){
                        BRICK.setColor(Color.YELLOW);
                    }
                    else if (ROWS == 6 || ROWS == 7){
                        BRICK.setColor(Color.GREEN);
                    }
                    else if (ROWS == 8 || ROWS == 9){
                        BRICK.setColor(Color.CYAN);
                    }
                add(BRICK);
                BRICKS++;
            }
            ROWS++;
            BRICKS = 0;
        }
    }

    private void createSides(){
        add(rightSide);
        add(leftSide);
        add(topSide);
        add(bottomSide);
    }

    private void createPaddle(){
        PADDLE.setFilled(true);
        add(PADDLE, WIDTH/2 - (PADDLE_WIDTH/2), HEIGHT - PADDLE_Y_OFFSET);
    }

    private void createBall(){
        BALL.setFilled(true);
        BALL.setLocation(WIDTH/2 - 18, HEIGHT/2);
        add(BALL);
    }

    private void play(){
        /* Add Title Text or Lives or Score */
        ballMovement();
    }

    private void ballMovement(){
        BRICK_COUNT = (NBRICKS_PER_ROW*NBRICK_ROWS);
        while (BRICK_COUNT != 0){
            BALL.move(ballXVelocity(), ballYVelocity());
            pause(5);
            checkXCollision();
            checkYCollision();
        }
    }

    public int ballXVelocity(){
        boolean x = checkXCollision();
        if (x == true){
            BALL_X_VELOCITY = -INITIAL_X_VELOCITY;
            INITIAL_X_VELOCITY = BALL_X_VELOCITY;
        }
        else {BALL_X_VELOCITY = INITIAL_X_VELOCITY;}
        return BALL_X_VELOCITY;
    }

    public int ballYVelocity(){
        boolean y = checkYCollision();
        if (y == true){
            BALL_Y_VELOCITY = -INITIAL_Y_VELOCITY;
            INITIAL_Y_VELOCITY = BALL_Y_VELOCITY;
        }
        else {BALL_Y_VELOCITY = INITIAL_Y_VELOCITY;}
        return BALL_Y_VELOCITY;
    }

    private boolean checkXCollision(){
        double ballX = BALL.getX();
        double ballY = BALL.getY();
        GObject colObjLeft = getElementAt(ballX, ballY - BALL_RADIUS);
        GObject colObjRight = getElementAt(ballX + BALL_RADIUS*2, ballY- BALL_RADIUS);
        if (ballX <= 0 || ballX + (BALL_RADIUS*2) >= APPLICATION_WIDTH){
            return true;
        }
        else if (colObjLeft != null){

            return true;
        }
        else if (colObjRight != null){

            return true;
        }
        else {return false;}
    }

    private boolean checkYCollision(){
        double ballX = BALL.getX();
        double ballY = BALL.getY();
        GObject colObjTop = getElementAt(ballX+ BALL_RADIUS, ballY - 1);
        GObject colObjBot = getElementAt(ballX + BALL_RADIUS, ballY + (BALL_RADIUS*2) + 1);
        if(colObjBot == PADDLE){
            return true;
        } 
        else if (ballY <= 0){
            return true;
            }
        else if (colObjTop != null && colObjTop != BALL){
            remove(colObjTop);
            return true;
        }   
        else if (colObjBot != null && colObjBot != PADDLE && colObjBot != BALL){
            remove(colObjBot);
            return true;
        }
        else {return false;}
    }

    public void mouseMoved(MouseEvent e){
        if (e != null){     
            int x = e.getX();
            PADDLE.setLocation(x - (PADDLE_WIDTH/2), HEIGHT - PADDLE_Y_OFFSET);
        }
    }

    /*public void paddleLocation(dx,dy);*/
        /*int x = */

    public GRect PADDLE = new GRect(PADDLE_WIDTH, PADDLE_HEIGHT);
    private GArc BALL = new GArc(BALL_RADIUS*2, BALL_RADIUS*2, 0,360);
    /*private GOval BALL = new GOval(BALL_RADIUS*2, BALL_RADIUS*2);*/
    private int BRICK_COUNT;
    private int BALL_Y_VELOCITY;
    private int BALL_X_VELOCITY;
    private int INITIAL_Y_VELOCITY = 1;
    private RandomGenerator rgen = RandomGenerator.getInstance();
    private int INITIAL_X_VELOCITY = rgen.nextInt(2);
    private GLine rightSide = new GLine (WIDTH, 0, WIDTH, HEIGHT );
    private GLine leftSide = new GLine (0, 0, 0, HEIGHT);
    private GLine topSide = new GLine (0, 0, WIDTH, 0);
    private GLine bottomSide = new GLine (0, HEIGHT, WIDTH, HEIGHT);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

终弃我 2024-11-07 16:05:20

看来您对 checkXCollisioncheckYCollision 的额外调用是问题所在。

您可以在 ballMovement 中直接调用它们,并且每个函数也会在 Velocity 方法内部调用。

要获取 Ball.move 的参数,您可以调用 Velocity 方法,该方法会检查碰撞并移除砖块。但是,在移动球之后,您将立即检查碰撞并再次移除。因此,当 ballMovement 下次运行时,砖块已经被移除,并且 Velocity 方法内的碰撞检测不起作用。

由于您没有对 ballMovement 中的碰撞返回值执行任何操作,因此您可能不需要它们。

It looks like your extra calls to checkXCollision and checkYCollision are the problem.

You call them directly as part of ballMovement, and each are also called inside the Velocity methods.

To get the params for Ball.move, you call the Velocity methods, which check for a collision and remove the brick. But, right after moving the ball, you're checking for collisions and removing again. So, when ballMovement gets run the next time, the bricks have already been removed, and the collision detection inside the Velocity methods doesn't work.

Since you're not doing anything with the collision return values in ballMovement, you probably don't need them.

画中仙 2024-11-07 16:05:20

欢迎来到SO,很好的第一个问题。

while (BRICK_COUNT != 0){
     BALL.move(ballXVelocity(), ballYVelocity());
     pause(5);
     checkXCollision();
     checkYCollision();
}

我认为错误在于在主循环中调用 check*Collision() 和在 ball*Velocity() 方法中调用

如果在 ball*Velocity() 方法之一中发现碰撞,则砖块将被移除,方向会反转,并且看起来不错。

但是,如果在直接调用 check*Collision() 时发现碰撞,则无法反转方向。

但恐怕修复不仅仅是删除这两行。 (但是试一试。:)当球在 X 和 Y 的角落碰撞时会发生什么?我认为事实上,您正在两个不同的函数中检查球速度,可能会在两个不同的函数中改变方向,并且不会在“它们之间”传递知识,因此当球击中时,您的碰撞代码角不正确。 (checkXCollision(),通过 ballXVelocity() 调用,可能会移除通过 ballYVelocity()< 调用 checkYCollision() 的砖块/code>,需要确定是否需要改变方向。)

您可能需要重写函数来同时计算 X 和 Y 碰撞,这样您就可以移除一两个砖块根据需要。

我希望这有帮助。

Welcome to SO, great first question.

while (BRICK_COUNT != 0){
     BALL.move(ballXVelocity(), ballYVelocity());
     pause(5);
     checkXCollision();
     checkYCollision();
}

I think the error is in calling check*Collision() in your main loop and in your ball*Velocity() methods.

If the collision is found in one of the ball*Velocity() methods, then the brick is removed, course reversed, and seems fine.

But if the collision is found in the direct calls to check*Collision(), then you're unable to reverse direction.

But I'm afraid the fix is going to be more than just removing these two lines. (But give that a shot. :) What happens when the ball collides in a corner, both X and Y? I think the fact that you're checking ball velocity in two different functions, possibly changing directions in two different functions, and not passing knowledge 'between them', that your collision code when the ball hits in a corner isn't correct. (checkXCollision(), called via ballXVelocity(), might remove a brick that checkYCollision(), called via ballYVelocity(), needs in order to determine if it needs to change direction.)

You might want to re-write the functions to calculate the X and Y collisions simultaneously, so you can remove one or two bricks as needed.

I hope this helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文