2014-01-16 181 views
3

我一直在研究一個突破遊戲,幾乎所有事情都做了,除了磚頭碰撞。球在牆壁和球拍上反彈的很好,但當涉及到磚塊時,它會直接穿過它們。我很確定問題出在主類的checkBrick()部分,但不知道該怎麼做。磚碰撞Java

主類:

import java.awt.*; 
import java.awt.event.KeyEvent; 
import java.applet.*; 
import java.util.Random; 
import javax.swing.JOptionPane; 

public class Breakout extends Applet implements Runnable { 
    Ball ball = new Ball(); 
    Paddle paddle = new Paddle(135, 375); 
    Brick[] brick = new Brick[50]; 
    private int bX[] = new int[50]; 
    private int bY[] = new int[50]; 
    private int bW[] = new int[50]; 
    private int bH[] = new int[50]; 
    Thread t; 
    Random trajectory = new Random(); 
    boolean lose; 
    Image buffer = null; 

    // The life cycle of the Applet 
    // Sets up window 
    public void init() { 
     setSize(377, 500); 
     buffer = createImage(377, 500); 
     // setBackground(Color.black); 
     System.out.println("init()"); 
    } 

    public void start() { 
     if (t == null) { 
      t = new Thread(this); 
      t.start(); 
     } 
     System.out.println("start()"); 
    } 

    public void run() { 
     System.out.println("run()"); 
     Thread.currentThread().setPriority(Thread.MIN_PRIORITY); 

     while (!lose) { 
      ball.move(); 
      paddle.move(); 
      checkWall(); 
      checkPaddle(); 
      checkBrick(); 
      ball.move(); 

      repaint(); 

      try { 
       Thread.sleep(30); 
      } catch (InterruptedException ex) { 
      } 
      Thread.currentThread().setPriority(Thread.MAX_PRIORITY); 
     } 

     JOptionPane.showMessageDialog(null, "Game Over"); 
     System.out.println("Termintated"); 
     System.exit(0); 
    } 

    public void stop() { 
     System.out.println("stop()"); 
    } 

    public void destroy() { 
     System.out.println("destroy()"); 
    } 

    public void paint(Graphics g) { 
     Graphics screen = null; 
     screen = g; 
     g = buffer.getGraphics(); 

     g.setColor(Color.black); 
     g.fillRect(0, 0, 377, 500); 
     createBricks(g); 
     createPaddle(g); 
     createBall(g); 

     screen.drawImage(buffer, 0, 0, this); 
    } 

    public void update(Graphics g) { 
     paint(g); 
    } 

    private void createBricks(Graphics g) { 
     int brickIndex = 0; 
     int brickX = 15, brickY = 160; 
     int brickW = 30, brickH = 10; 
     for (int i = 0; i <= 4; i++) { 
      brickX = 15; 
      brickY -= 20; 

      for (int n = 0; n < 10; n++) { 
       brick[brickIndex] = new Brick(); 
       brick[brickIndex].setBounds(brickX, brickY, brickW, brickH); 
       bX[brickIndex] = brick[brickIndex].x(); 
       bY[brickIndex] = brick[brickIndex].y(); 
       bW[brickIndex] = brick[brickIndex].w(); 
       bH[brickIndex] = brick[brickIndex].h(); 
       brick[brickIndex].setColor(i); 
       brick[brickIndex].paint(g); 
       brickIndex++; 
       brickX += 35; 
      } 
     } 

    } 

    private void createPaddle(Graphics g) { 
     paddle.paint(g); 

    } 

    private void createBall(Graphics g) { 
     ball.paint(g); 
    } 

    private void checkWall() { 
     // If ball hits right wall it will bounce 
     if ((ball.getX() + ball.getR()) >= 380) { 
      ball.setVX(trajectory.nextInt(2) + -3); 
     } 

     // If ball hits left wall it will bounce 
     if ((ball.getX() - ball.getR()) < -10) { 
      ball.setVX(trajectory.nextInt(4) + 1); 
     } 

     // If ball hits ceiling it will bounce 
     if ((ball.getY() + ball.getR()) < 12) 
      ball.setVY(trajectory.nextInt(5) + 1); 

     // If ball goes through floor it will subtract a life 
     if ((ball.getY() + ball.getR()) > 515) 
      lose = true; 

    } 

    private void checkBrick() { 
     for (int i = 0; i < 50; i++) { 
      int tempX, tempY, tempW, tempH; 
      tempX = bX[i]; 
      tempY = bY[i]; 
      tempW = bW[i]; 
      tempH = bH[i]; 

      if ((ball.getX() + ball.getR()) < (tempX + tempW) 
        && (ball.getX() + ball.getR()) >= tempX) { 
       if ((ball.getY() + ball.getR()) > (tempY + tempH) 
         && (ball.getY() + ball.getR()) <= tempY) { 
        System.out.println("Brick " + i + " has been hit."); 
       } 
      } 
     } 
    } 

    private void checkPaddle() { 
     // Check for paddle 
     if ((ball.getX() + ball.getR()) < (paddle.getX() + 100) 
       && (ball.getX() + ball.getR()) >= paddle.getX() + 5) { 
      if ((ball.getY() + ball.getR()) > (paddle.getY() - 5) 
        && (ball.getY() + ball.getR()) <= (paddle.getY() + 5)) { 
       ball.setVX((trajectory.nextInt(7) + -2) + 1); 
       ball.setVY(trajectory.nextInt(1) + -3); 
      } 
     } 
    } 

    // Key Detectors 
    public boolean keyDown(Event e, int key) { 
     if (key == Event.RIGHT) { 
      paddle.setVX(0); 
      if ((paddle.getX() + 100) < 377) 
       paddle.setVX(10); 
     } 
     if (key == Event.LEFT) { 
      paddle.setVX(0); 
      if (paddle.getX() > 0) 
       paddle.setVX(-10); 
     } 

     return true; 
    } 

    // To make sure it doesn't just keep moving one way 
    public boolean keyUp(Event e, int key) { 
     paddle.setVX(0); 
     return true; 
    } 
} 

球類別:

import java.awt.Color; 
import java.awt.Graphics; 
import java.util.Random; 

public class Ball 
{ 
    private int x, y; //Position 
    private int vx, vy; //Velocity 
    private int r; //radius 

    //constructor 
    public Ball() 
    { 
     x = 177; 
     y = 315; 
     vx = 0; 
     vy = 5; 
     r = 15; 
    } 

    public void paint(Graphics g) 
    { 
     g.setColor(Color.white); 
     g.fillOval(x, y, r, r); 

    } 

    //returns the x of origin 
    public int getX() 
    { 
     return x; 
    } 

    //returns the y of origin 
    public int getY() 
    { 
     return y; 
    } 
    public int getVX() 
    { 
     return vx; 
    } 

    //returns the y of origin 
    public int getVY() 
    { 
     return vy; 
    } 

    //returns the radius r of the ball 
    public int getR() 
    { 
     return r; 
    } 

    //sets the velocity of x to a different value 
    public void setVX(int vx) 
    { 
     this.vx = vx; 
    } 

    //sets the velocity of y to a different value 
    public void setVY(int vy) 
    { 
     this.vy = vy; 
    } 

    //sets the x value 
    public void setX(int x) 
    { 
     this.x = x; 
    } 

    //sets the y value 
    public void setY(int y) 
    { 
     this.y = y; 
    } 

    //starts making the ball move by changing its coords 
    public void move() 
    { 
     x+= vx; 
     y+= vy; 
    } 

} 

槳類別:

import java.awt.Color; 
import java.awt.Graphics; 

public class Paddle { 

    // declares variables for x and y coordinates 
    int x, y; 
    //The velocity of to move paddle 
    int vx; 

    // constructor that takes in x and y coordinates for paddle 
    public Paddle(int x, int y) 
    { 
     this.x = x; 
     this.y = y; 
    } 

    public void paint(Graphics g) 
    { 
     // paints paddle 
     g.setColor(Color.WHITE); 
     g.fillRect(x, y, 100, 15); 
     g.setColor(Color.GREEN); 
     g.drawRect(x, y, 100, 15); 
    } 

    // gets x coordinate of paddle 
    public int getX() { 
     return x; 
    } 

    // sets x coordinate of paddle 
    public void setX(int x) { 
     this.x = x; 
    } 

    // gets y coordinate of paddle 
    public int getY() { 
     return y; 
    } 

    // sets y coordinate of paddle 
    public void setY(int y) { 
     this.y = y; 
    } 

    public void setVX(int vx) 
    { 
     this.vx = vx; 
    } 
    //Moves the paddle 
    public void move() 
    { 
     x+=vx; 
    } 
} 

磚類別:

import java.awt.Color; 
import java.awt.Graphics; 


public class Brick 
{ 
    private Color color =(Color.cyan); 
    private int x, y, w, h; 

    public Brick() 
    { 
     //Garbage values that are there just for declaration 
     x = 0; 
     y = 0; 
     w = 10; 
     h = 10; 
    } 

    //Sets color for the brick 
    public void setColor(int paintC) 
    { 
     switch(paintC) 
     { 
      case 0: 
       color = (Color.magenta); 
       break; 
      case 1: 
       color = (Color.blue); 
       break; 
      case 2: 
       color = (Color.yellow); 
       break; 
      case 3: 
       color = (Color.orange); 
       break; 
      default: 
       color = (Color.red); 
       break; 
     } 
    } 

    //Sets the location then size of the brick 
    public void setBounds(int x, int y, int w, int h) 
    { 
     this.x = x; 
     this.y = y; 
     this.w = w; 
     this.h = h; 
    } 

    //returns x value 
    public int x() 
    { 
     return this.x; 
    } 

    //returns y value 
    public int y() 
    { 
     return this.y; 
    } 

    //returns width value 
    public int w() 
    { 
     return this.w; 
    } 

    //returns height value 
    public int h() 
    { 
     return this.h; 
    } 


    //Sets x for the brick 
    public void setX(int x) 
    { 
     this.x = x; 
    } 

    //Sets y for the brick 
    public void setY(int y) 
    { 
     this.y = y; 
    } 

    public void setW(int w) 
    { 
     this.w = w; 
    } 

    public void setH(int h) 
    { 
     this.h = h; 
    } 

    public void paint(Graphics g) 
    { 
     g.setColor(color); 
     g.fillRect(x, y, w, h); 
     g.setColor(Color.green); 
     g.drawRect(x, y, w, h); 
    } 
} 
+3

真的? 「這是你以前從未見過的440行代碼,請找到這個bug」。你需要付出更多的努力! – John3136

+1

我會建議看看2D圖形幾何類,這將會照顧這大部分...... – MadProgrammer

+0

'setSize'和'System.exit'不應該在小應用程序的上下文中使用 – MadProgrammer

回答

2

我已經開始運行你的代碼了,坦率地說,不能試圖弄清楚你的邏輯,但我相信你試圖推斷出的是如果磚「包含」球,而不是如果球相交與磚。

你不在乎多少球或磚相交,只有當他們做...例如...

private void checkBrick() { 

    int tx = ball.getX(); 
    int ty = ball.getY(); 
    int tw = ball.getR(); 
    int th = ball.getR(); 

    tw += tx; 
    th += ty; 

    for (int i = 0; i < 50; i++) { 
     int tempX, tempY, tempW, tempH; 
     tempX = bX[i]; 
     tempY = bY[i]; 
     tempW = bW[i]; 
     tempH = bH[i]; 

     int rw = tempW + tempX; 
     int rh = tempH + tempY; 

     //  overflow || intersect 
     if ((rw < tempX || rw > tx) && 
      (rh < tempY || rh > ty) && 
       (tw < tx || tw > tempX) && 
       (th < ty || th > tempY)) { 
      System.out.println("Hit"); 
     } 
    } 
} 

現在,我偷了這個從Rectangle#intersects

基本上,如果你從2D圖形API使用的幾何課,你可以轉降低這...

private void checkBrick() { 

    Rectangle b = new Rectangle(ball.getX(), ball.getY(), ball.getR(), ball.getR()); 

    for (int i = 0; i < 50; i++) { 
     int tempX, tempY, tempW, tempH; 
     tempX = bX[i]; 
     tempY = bY[i]; 
     tempW = bW[i]; 
     tempH = bH[i]; 

     Rectangle brick = new Rectangle(tempX, tempY, tempW, tempH); 

     System.out.println("brick = " + brick); 
     if (b.intersects(brick)) { 
      System.out.println("Break"); 
     } 
    } 
} 

而且,是的,我確實運行過您的代碼

+0

非常感謝你,對於瘋狂的發生感到抱歉,這是一個團體項目,我們都是初學者,幾乎不知道編程。我們現在遇到的一個問題是,我們不能讓磚塊在擊中時消失。我嘗試使用brick.setLocation(0,400)設置磚塊在屏幕外的位置(效率非常低,但我們很匆忙),但它似乎沒有做任何事情。 – Sunny

+0

如果您實際上將'Brick'保留在數組中而不是存在點,則可以簡單地將數組位置設置爲'null'並跳過檢查 - 而且,在每個繪製週期內不應該「重新創建」它們。在啓動時設置它們,並簡單地更新每個週期的屏幕... – MadProgrammer

+0

非常感謝,看起來這可能很痛苦,但它真的有幫助。 – Sunny

1

問題在於方法checkBrick()沒有改變任何東西,只是在球與磚發生碰撞時纔打印。

您可能想要更改Ball速度,就像您在checkWall()checkPaddle()中所做的那樣。

private void checkBrick() { 
    for (int i = 0; i < 50; i++) { 
     ... 
     if (...) { 
      ball.setVX(...); // Add these lines setting the correct values 
      ball.setVY(...); 
     } 
    } 
} 

您可能還想檢查您的if-conditions是否正確,並做你的預期。

+0

從我的實驗來看,它從來沒有達到'真正'的條件,所以'System.out'永遠不會被調用... – MadProgrammer

0

假設tempH爲正,

((ball.getY() + ball.getR()) > (tempY + tempH) 
        && (ball.getY() + ball.getR()) <= tempY) 

不能永遠是真實的。 >需要爲<<=需要爲>=

此外,如果磚被擊中,您需要採取某種行動,而不是僅僅打印出事實。對不起,我不知道應該發生什麼 - 磚塊消失了嗎?還是球彈跳?或兩者?

0

您正在檢查球是否在磚的左側和右側之間,但是接着檢查球是否位於磚的上方和下方,因爲您已經混合了大於和小於混合的球。球的中心也需要從它的Y位置中減去。

if ((ball.getY() + ball.getR()) **>** (tempY + tempH) && 
    (ball.getY() **+** ball.getR()) **<=** tempY) 

可能是

if ((ball.getY() + ball.getR()) < (tempY + tempH) && 
    (ball.getY() - ball.getR()) >= tempY) 

,但我建議,如果發現球的頂部是磚的頂部和底部之間,或者如果球的底部是頂部之間磚的底部:

if (((ball.getY() + ball.getR()) < (tempY + tempH) && (ball.getY() - ball.getR()) >= tempY)) || 
    ((ball.getY() - ball.getR()) < (tempY + tempH) && (ball.getY() - ball.getR()) >= tempY))) { 
    CODE 
} 

而且使用類似的邏輯磚的左右兩側之間找到

+0

試過了,在我的測試中似乎沒有什麼區別。據我所知,「球」不能被「包含」在「磚」內,但我可能誤解了邏輯...... – MadProgrammer

0

第二個答案(除了我認爲也是問題的其他答案之外),您的邏輯是詢問球是否包含在一塊磚,但是當你創造球時,它的半徑大於磚的高度,所以即使糾正這個邏輯也不能解決問題。

你應該重構代碼,使其讀出像自然語言,這將有很大的幫助與調試,即在磚類

(或擺在首位編寫更少的錯誤!):

public int bottom() 
{ 
    return y; 
} 
public int top() 
{ 
    return y + h; 
} 

在球類:

public int bottom() 
{ 
    return y - r; 
} 
public int top() { 
    return y + r; 
} 

然後在主類:

private boolean withinY(brick) { 
    return (ball.bottom => brick.bottom() && ball.top =< brick.top()); 
} 

則邏輯讀取更好(僞):

foreach brick in wall { 
    if (ball.withinY(brick) and ball.withinX(brick)) 
     BAM!! 
}