3

I have been working on a Breakout game and have just about everything done except for the brick collision. The ball bounces of the wall and paddle fine, but when it comes to the brick it goes straight through them. I'm pretty sure the problem is in the checkBrick() part of the main class, but have no idea what to do about it.

Main Class:

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

Ball Class:

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

}

Paddle Class:

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

Brick Class:

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);
    }
}
Sunny
  • 41
  • 1
  • 3
  • 3
    Seriously? "Here is 440ish lines of code you have never seen before. Please find the bug". You need to put in a bit more effort than that! – John3136 Jan 16 '14 at 04:05
  • 1
    I would recommend taking a look at the 2D Graphics geometry class, which would take care of most of this... – MadProgrammer Jan 16 '14 at 04:06
  • `setSize` and `System.exit` should NEVER be used within the context of the applet – MadProgrammer Jan 16 '14 at 04:08
  • You never asked a question. – Gene Jan 16 '14 at 04:26
  • 1) Why code an applet? If it is due to spec. by teacher, please refer them to [Why CS teachers should stop teaching Java applets](http://programmers.blogoverflow.com/2013/05/why-cs-teachers-should-stop-teaching-java-applets/). 2) Why AWT rather than Swing? See my answer on [Swing extras over AWT](http://stackoverflow.com/a/6255978/418556) for many good reasons to abandon using AWT components. – Andrew Thompson Jan 16 '14 at 04:37
  • See [Collision detection with complex shapes](http://stackoverflow.com/questions/14574045/collision-detection-with-complex-shapes/14575043#14575043) for tips on how to achieve the collision detection using the power of Java-2D. – Andrew Thompson Jan 16 '14 at 04:38

5 Answers5

2

I've begin running over your code, quite frankly can't be bothered trying to figure out your logic, but what I believe you're trying to deduce is if the brick "contains" the ball, rather then if the ball intersects with the brick.

You don't care how much of the ball or brick are intersecting, only if the they do...for example...

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

Now, I stole this from Rectangle#intersects

Basically, if you used the geometry class from the 2D Graphics API, you could reduce this down to...

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

And, yes, I did actually run your code

MadProgrammer
  • 323,026
  • 21
  • 204
  • 329
  • Thank you so much, sorry about the madness going on, this has been a group project and we are both beginners that pretty much have no idea about programming. A problem we are encountering now is that we cannot get the brick to disappear when hit. I've tried setting the brick's location outside the screen(very inefficient but we're in a hurry) using brick.setLocation(0, 400), but it doesn't seem to do anything. – Sunny Jan 16 '14 at 05:48
  • If you actually kept `Brick` in the array instead of there points, you could simply set the array position to `null` and skip checking - Also, you shouldn't be "recreating" them on each paint cycle. Set them up when it starts and simply update the screen on each cycle... – MadProgrammer Jan 16 '14 at 05:59
  • Thanks a ton, it's probably been painful too look at this, but it has genuinely helped. – Sunny Jan 16 '14 at 06:05
1

The problem is that the method checkBrick() is not changing anything, it is just printing if the ball has a collision with the brick.

You may want to change the Ball velocity, as you did within checkWall() and checkPaddle().

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

You may also want to check if your if-conditions are correct, and do what you expected.

Christian
  • 31,246
  • 6
  • 45
  • 67
0

Assuming tempH is positive,

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

can't ever be true. The > needs to be < and the <= needs to be >=.

Additionally, you'll need to take some kind of action if the brick is hit, rather than just printing out the fact. Sorry, I'm not sure what's supposed to happen - does the brick disappear? Or the ball bounce? Or both?

Dawood ibn Kareem
  • 68,796
  • 13
  • 85
  • 101
0

You're checking if the ball is between the left and right side of the brick, but then checking if the ball is both above AND below the brick, because you've got your greater than and less than's mixed up. Also the center of the ball needs to be subtracted from it's Y position.

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

could be

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

but I'd suggest finding if the top of the ball is between the top and bottom of the brick, OR if the bottom of the ball is between the top and bottom of the brick:

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

And use similar logic for finding between left and right sides of the brick

Griknok
  • 328
  • 2
  • 12
  • Tried, didn't seem to make a difference in my testing. From what I understand, the "ball" can not be "contained" within the "brick", but I might misunderstand the logic... – MadProgrammer Jan 16 '14 at 04:32
0

Second answer (in addition to other answer which I believe is ALSO a problem), your logic is asking if the ball is contained within a brick, but when you create the ball its radius is greater than the height of a brick, so even correcting that logic won't fix the problem.

You should refactor your code to make it read out like natural language, this would help a lot with debugging (or writing less bugs in the first place!) i.e.

in brick class:

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

in ball class:

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

then in main class:

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

then the logic reads nicer (psuedo):

foreach brick in wall {
    if (ball.withinY(brick) and ball.withinX(brick))
        BAM!!
}
Griknok
  • 328
  • 2
  • 12