2013-09-30 17 views
2

我是Java新手,正在从斯坦福大学YouTube课程中学习。只有一块砖在突破游戏中消失

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

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

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

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; 
} 
+0

Madsonic,你尝试调试应用程序?把断点放在一些相关的 - 在你看来 - 放置和检查会发生什么? –

+1

我倾向于从你对问题的描述中怀疑你在为你的领域添加砖块时做错了什么。作为附注,不要将对象与'=='比较!使用'。等于'方法。 – Aurand

+0

@Piotr是的,我已经试图调试我的程序几天了,但无济于事。我很抱歉什么是断点?这里仍然是小菜一碟! – Gerald

回答

4

正是我想。 Look - 你的课堂上有一个名为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; 
    } 
} 
+0

我明白了!所以如果我想删除其他砖块,我应该如何引用它们? remove()中的参数是什么? – Gerald

+0

@madsonic检查我更新的答案。希望能帮助到你! –

+0

我感谢你的努力。然而,经过进一步的研究,我意识到我的代码是可行的,这意味着我不必采用新的方法,即阵列和平等。我不愿意使用你的答案,因为如果我遵循斯坦福德课程,他们还没有教会我们这些技巧(阵列和平等),并且可以完成整个突破游戏。我发现另一名学生有类似的代码和他的游戏[点击这里查看他的代码](https://sites.google.com/site/qasimisonline/my-stuff/breakout-game-code-java-)工作得很好。我们似乎在这里错过了一些东西。 – Gerald