【问题标题】:Brick Collision Java [closed]砖碰撞Java [关闭]
【发布时间】:2014-02-04 20:21:09
【问题描述】:

我一直在开发一个 Breakout 游戏,除了砖块碰撞之外,我几乎完成了所有工作。球在墙上弹跳并很好地划动,但是当它碰到砖块时,它会直接穿过它们。我很确定问题出在主类的 checkBrick() 部分,但不知道该怎么办。

主类:

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);
    }
}

【问题讨论】:

  • 认真的吗? “这是你从未见过的 440 行代码。请找出错误”。你需要付出更多的努力!
  • 我建议看一下 2D Graphics 几何类,它可以解决大部分问题...
  • setSizeSystem.exit 绝不应该在小程序的上下文中使用
  • 你从来没有问过问题。
  • 1) 为什么要编写小程序?如果是由于规范。老师请发给Why CS teachers should stop teaching Java applets。 2) 为什么选择 AWT 而不是 Swing?请参阅我在 Swing extras over AWT 上的回答,有很多放弃使用 AWT 组件的充分理由。

标签: java collision-detection physics game-physics breakout


【解决方案1】:

我已经开始检查你的代码,坦率地说,我不想费心去弄清楚你的逻辑,但我相信你试图推断的是砖是否“包含”球,而不是如果球与砖相交。

你不关心球或砖有多少相交,只要它们相交......例如......

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");
        }
    }
}

而且,是的,我确实运行了你的代码

【讨论】:

  • 非常感谢,对发生的疯狂感到抱歉,这是一个小组项目,我们都是初学者,对编程几乎一无所知。我们现在遇到的一个问题是我们无法让砖块在被击中时消失。我尝试使用brick.setLocation(0, 400) 将砖块的位置设置在屏幕外(效率非常低,但我们很着急),但它似乎没有做任何事情。
  • 如果您实际上将 Brick 保留在数组中而不是那里的点,您可以简单地将数组位置设置为 null 并跳过检查 - 此外,您不应该“重新创建”它们每个油漆周期。在启动时设置它们,并在每个循环中简单地更新屏幕...
  • 非常感谢,看这个可能也很痛苦,但它确实有帮助。
【解决方案2】:

问题是 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 是否正确,并按照您的预期进行操作。

【讨论】:

  • 根据我的实验,它永远不会达到true 条件,因此永远不会调用System.out...
【解决方案3】:

假设tempH 是正数,

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

永远不可能是真的。 &gt; 需要是 &lt;&lt;= 需要是 &gt;=

此外,如果砖块被击中,您将需要采取某种行动,而不仅仅是打印出事实。抱歉,我不确定会发生什么 - 砖会消失吗?还是球反弹?还是两者兼有?

【讨论】:

    【解决方案4】:

    第二个答案(除了我认为也是一个问题的其他答案),您的逻辑是询问球是否包含在砖块中,但是当您创建球时,它的半径大于砖块的高度,所以即使纠正这个逻辑也不能解决问题。

    你应该重构你的代码,让它像自然语言一样读出来,这对调试有很大帮助(或者首先编写更少的错误!)即

    在砖类中:

    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!!
    }
    

    【讨论】:

      【解决方案5】:

      您正在检查球是否在砖的左侧和右侧之间,然后检查球是否在砖的上方和下方,因为您的大于和小于混淆了。球的中心也需要从它的 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
      }
      

      并使用类似的逻辑来查找砖块的左右两侧

      【讨论】:

      • 试过了,似乎对我的测试没有影响。据我了解,“球”不能“包含”在“砖”内,但我可能误解了逻辑......
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-11
      相关资源
      最近更新 更多