2013-09-30 20 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