突破游戏中只有一块砖消失

时间:2013-09-30 05:53:18

标签: java collision-detection breakout

我是Java新手,正在学习来自YouTube的Stanford讲座。

所以我正在尝试他们的作业breakout game,到目前为止一直很好。我有我的所有砖块,球和桨包括游戏的机制,但是当我运行游戏时,只有一块砖被击球时可以被移除。见this。那块砖恰好是添加到画布上的最后一块砖。

球飞过所有其他砖块,没有任何效果。相关代码如下。

我在这里缺乏关于getElementAt的一些重要知识吗?我觉得getCollidingObject没有分配给碰撞器,这使得碰撞检测有问题。我希望有人可以就此启发我!

private void addBallMotion(){
// y component of starting velocity; pixels per second
  vy = 3.0;

/* x component of starting velocity; pixels per second
 * which ranges according to the random generator
 * can be negative or positive, ball can go left or right with equal chances
 */
  vx = rgen.nextDouble(1.0, 3.0);
  if (rgen.nextBoolean(0.5)){
    vx = -vx;
  }
  while (true){
    ball.move(vx, vy);
    checkCollision();
    pause(FPS);
  }
}

private void checkCollision(){
  checkWallCollision();
  checkBrickAndPaddleCollision();
}

private void checkWallCollision(){
  //checks for left or right collision
  if ( (ball.getX() < leftBounds.getX() ) || (ball.getX() + BALL_RADIUS * 2 > rightBounds.getX()) ){
    vx = -vx;
  }
  //checks for top or bottom collision
  if ( (ball.getY() < topBounds.getY() ) || (ball.getY() + BALL_RADIUS * 2 > bottomBounds.getY()) ){
    vy = -vy;
  }
}

private void checkBrickAndPaddleCollision(){
  GObject collider = getCollidingObject();
  if (collider == brick){
    remove(collider);
    vy = -vy;
  }
  if (collider == paddle){
    vy = -vy;
  }
}

//check for collision at the 4 edges of the ball
//starting with the left and going clockwise
private GObject getCollidingObject(){
  GObject  ballLeft= getElementAt (ball.getX() - 1, ball.getY() + BALL_RADIUS);
  GObject  ballRight= getElementAt (ball.getX() + BALL_RADIUS * 2 + 1, ball.getY() + BALL_RADIUS);
  GObject  ballTop = getElementAt (ball.getX() + BALL_RADIUS * 2, ball.getY() - 1);
  GObject  ballBottom= getElementAt (ball.getX() + BALL_RADIUS, ball.getY() + BALL_RADIUS * 2 + 1);

  if (ballLeft != null){
    return (ballLeft);
  }
  else if (ballTop != null){
    return (ballTop);
  }
  else if (ballRight != null){
    return (ballRight);
  }
  else if (ballBottom != null){
    return (ballBottom);
  }
  return (null);
}

private GRect paddle;  // creates a paddle that only moves linearly according to mouses' x coordinate
private GRect brick;
private GOval ball;
private double vx, vy;  // x and y components of the ball's velocity
//private GObject collider;

以下是整个计划:

import acm.graphics.*;
import acm.program.*;
import acm.util.*;

import java.applet.*;
import java.awt.*;
import java.awt.event.*;

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;

    /** Offset of the side bricks from the sides of game window */
  private static final int BRICK_X_OFFSET = ((WIDTH - NBRICKS_PER_ROW * (BRICK_WIDTH + BRICK_SEP) + BRICK_SEP) / 2);

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

    /**  Number of frames per second */
  private static final int FPS = 1;

    /* Method: run() */
    /** Runs the Breakout program. */
  public void run() {
    addMouseListeners();
    addWorld();
    //  runGame();
  }
  private void addWorld(){
    setSize (APPLICATION_WIDTH, APPLICATION_HEIGHT);
    addPlayingBox();
    addBricks();
    addPaddle();
    addBall();
    //  addCounter();
  }

  //adds the bound area onto screen
  private void addPlayingBox(){
    topBounds = new GLine (0, 0, WIDTH, 0);
    bottomBounds = new GLine (0, HEIGHT, WIDTH, HEIGHT);
    leftBounds = new GLine (0, 0, 0, HEIGHT);
    rightBounds = new GLine (WIDTH, 0, WIDTH, HEIGHT);
    add (topBounds);
    add (bottomBounds);
    add (leftBounds);
    add (rightBounds);
  }

  private void addBricks(){
    for (int i = 0; i < NBRICK_ROWS; i++){
      int y = BRICK_Y_OFFSET + (i * (BRICK_HEIGHT + BRICK_SEP));

      for (int j = 0; j < NBRICKS_PER_ROW; j++){
        int x = (BRICK_X_OFFSET) + (j * (BRICK_WIDTH + BRICK_SEP));
        brick = new GRect (x, y, BRICK_WIDTH, BRICK_HEIGHT );
        colorBrick(brick, i);
        add (brick);
      }
    }
  }

  // every consecutive 2 rows are colored the same
  private void colorBrick(GRect brick, int rowNumber){
    brick.setFilled (true);
    switch (rowNumber + 1) {
      case 1: case 2: brick.setColor(Color.red);
        break;
      case 3: case 4: brick.setColor(Color.orange);
        break;
      case 5: case 6: brick.setColor(Color.yellow);
        break;
      case 7: case 8: brick.setColor(Color.green);
        break;
      case 9: case 10:brick.setColor(Color.cyan);
        break;
    }
  }

  //adds paddle to screen
  private void addPaddle(){
    paddle = new GRect (PADDLE_WIDTH, PADDLE_HEIGHT);
    paddle.setFilled(true);
    paddle.setColor (Color.BLACK);
    add (paddle);
  }

  //creates motion for the paddle according to mouse movement
  public void mouseMoved(MouseEvent e){
    paddle.setLocation ((e.getX() - PADDLE_WIDTH / 2), (double) (HEIGHT - PADDLE_Y_OFFSET));

  /* checks if the paddle within the playing area
   * if not the paddles will stay at the extremities*/
    if ( paddle.getX() > (WIDTH - PADDLE_WIDTH)){
      paddle.setLocation((double) (WIDTH - PADDLE_WIDTH), (double) (HEIGHT - PADDLE_Y_OFFSET));
    }
    if ( paddle.getX() < 0){
      paddle.setLocation((double) 0, (double) (APPLICATION_HEIGHT - PADDLE_Y_OFFSET));
    }
  }

  private void addBall(){
    ball = new GOval (((WIDTH - BALL_RADIUS * 2) / 2), ((HEIGHT - BALL_RADIUS * 2) / 2),
              BALL_RADIUS * 2, BALL_RADIUS * 2);
    ball.setFilled(true);
    ball.setColor(Color.BLACK);
    add (ball);
    addBallMotion();
  }

  private void addBallMotion(){
  // y component of starting velocity; pixels per second
    vy = 3.0;

  /* x component of starting velocity; pixels per second
   * which ranges according to the random generator
   * can be negative or positive, ball can go left or right with equal chances
   */
    vx = rgen.nextDouble(1.0, 3.0);
    if (rgen.nextBoolean(0.5)){
      vx = -vx;
    }
    while (true){
      ball.move(vx, vy);
      checkCollision();
      pause(FPS);
    }
  }

  private void checkCollision(){
    checkWallCollision();
    checkBrickAndPaddleCollision();
  }

  private void checkWallCollision(){
    //checks for left or right collision
    if ( (ball.getX() < leftBounds.getX() ) || (ball.getX() + BALL_RADIUS * 2 > rightBounds.getX()) ){
      vx = -vx;
    }
    //checks for top or bottom collision
    if ( (ball.getY() < topBounds.getY() ) || (ball.getY() + BALL_RADIUS * 2 > bottomBounds.getY()) ){
      vy = -vy;
    }
  }

  private void checkBrickAndPaddleCollision(){
    GObject collider = getCollidingObject();
    if (collider == brick){
      remove(collider);
      vy = -vy;
    }
    if (collider == paddle){
      vy = -vy;
    }
  }

  //check for collision at the 4 edges of the ball
  //starting with the left and going clockwise
  private GObject getCollidingObject(){
    GObject  ballLeft= getElementAt (ball.getX() - 1, ball.getY() + BALL_RADIUS);
    GObject  ballRight= getElementAt (ball.getX() + BALL_RADIUS * 2 + 1, ball.getY() + BALL_RADIUS);
    GObject  ballTop = getElementAt (ball.getX() + BALL_RADIUS * 2, ball.getY() - 1);
    GObject  ballBottom= getElementAt (ball.getX() + BALL_RADIUS, ball.getY() + BALL_RADIUS * 2 + 1);

    if (ballLeft != null){
      return (ballLeft);
    }
    else if (ballTop != null){
      return (ballTop);
    }
    else if (ballRight != null){
      return (ballRight);
    }
    else if (ballBottom != null){
      return (ballBottom);
    }
    return (null);
  }

  private GRect paddle;  // creates a paddle that only moves linearly according to mouses' x coordinate
  private GRect brick;
  private GOval ball;
  private double vx, vy;  // x and y components of the ball's velocity
  private RandomGenerator rgen = RandomGenerator.getInstance();
  //private GObject collider;
  private GLine topBounds;  // creates a bounding box that is the playing area
  private GLine bottomBounds;
  private GLine leftBounds;
  private GLine rightBounds;
}

1 个答案:

答案 0 :(得分:4)

正如我想的那样。 看 - 您的班级中有一个名为brick的字段。它是GRect类型。在开始时,您正在调用addWorld()方法,该方法会调用addBricks()。现在检查你写的内容:

private void addBricks(){
    for (int i = 0; i < NBRICK_ROWS; i++){
        int y = BRICK_Y_OFFSET + (i * (BRICK_HEIGHT + BRICK_SEP));

        for (int j = 0; j < NBRICKS_PER_ROW; j++){
            int x = (BRICK_X_OFFSET) + (j * (BRICK_WIDTH + BRICK_SEP));
            brick = new GRect (x, y, BRICK_WIDTH, BRICK_HEIGHT );
            colorBrick(brick, i);
            add (brick);
        }
    }
}

那里发生了什么?你有一个循环,其中brick覆盖NBRICK_ROWS * NBRICKS_PER_ROW次,这导致brick字段成为屏幕上最后创建的砖。

基本上,你正在做类似的事情:

int x;
x = 5;
x = 6;
x = 8;
// x is 8 now 

checkBrickAndPaddleCollision()中,您只检查对撞机是否为brick。换句话说,这意味着,你正在检查它是否是最后一块 - 如果是,那么你将其删除。

首先,您应该创建一个砖块数组,而不仅仅是一个字段。

ArrayList<GRect> bricks;

而不是:

GRect brick;

然后在addBricks()方法中,您应该:

bricks.add(new GRect (x, y, BRICK_WIDTH, BRICK_HEIGHT));

而不是:

brick = new GRect (x, y, BRICK_WIDTH, BRICK_HEIGHT );

在此之后,在checkBrickAndPaddleCollision()中,您不应该检查:

if (collider == brick) {
     remove(collider);
     vy = -vy;
}

而是所有砖块:

for(GRect brick : bricks) {
    if (collider.equals(brick)) {  // Note that you should rather use .equals, instead of == as Aurand stated in his comment
         remove(collider);
         vy = -vy;
    }
}