Hi, I am trying to learn some basic game programming and already made simple pong game so I thought next step could be simple breakout. I already got ball and bat made by Rectangle. How about bricks, also Rectangle? If so it would be easy to break them just by using intersect(), but how to add those? And second question, what is the best way to modify the angle of the ball?

Recommended Answers

All 17 Replies

Okay I hesitated little with my question. Right after posting I realized that I can use object arrays. But how about angles?

By angles do you mean the changes in the x and y locations of the object as it moves?
If you change only the x value then the object moves horizontally. Changes in the y value moves the object vertically. Changes of both will move somewhere in between.

Yeah that much I know. I mean how I should determine about which angle the ball hits to te paddle or walls or brick. And I also got weird problem. Some of bricks wont destroy after first hit of ball.

Here's the code:

Board.java

package net.viped;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;

import javax.swing.JPanel;

public class Board extends JPanel{

    private boolean right = false;
    private boolean left = false;

    private boolean gameOn = true;

    private int dy = -2;
    private int dx = -2;

    Rectangle bat = new Rectangle();
    Rectangle ball = new Rectangle();
    Rectangle wall_left = new Rectangle();
    Rectangle wall_right = new Rectangle();
    Rectangle wall_top = new Rectangle();
    Brick[] bricks = new Brick[20];
    Saie saie = new Saie();
    public Board() {
        addKeyListener(new ListenKeys());
        setBackground(Color.white);
        setFocusable(true);
        gameInit();
        saie.start();
    }

    public void gameInit() {
        bat.setBounds(100, 450, 60, 4);
        ball.setBounds(300, 100, 10, 10);
        wall_left.setBounds(0, 0, 1, 480);
        wall_right.setBounds(601, 0, 1, 480);
        wall_top.setBounds(0, 0, 600, 1);
        for (int i = 0; i < bricks.length; i++) {
            bricks[i] = new Brick();
            bricks[i].setBounds(i*30, 30, 10, 5);
        }
    }

    public void paint(Graphics g) {
        super.paint(g);
        g.setColor(Color.green);
        g.fillRect(bat.x, bat.y, bat.width, bat.height);
        g.fillOval(ball.x, ball.y, ball.width, ball.height);

        g.setColor(Color.black);
        g.fillRect(wall_left.x, wall_left.y, wall_left.width, wall_left.height);
        g.fillRect(wall_right.x, wall_right.y, wall_right.width, wall_right.height);
        g.fillRect(wall_top.x, wall_top.y, wall_top.width, wall_top.height);

        for (int i = 0; i<bricks.length; i++) {
            if (bricks[i].isDestroyed()) {
                g.setColor(Color.black);
                g.fillRect(i*30, bricks[i].y, 32, 12);
                g.setColor(Color.black);
                g.fillRect(i*30+1, bricks[i].y+1, 30, 10);  
            } else {
                g.setColor(Color.black);
                g.fillRect(i*30, bricks[i].y, 32, 12);
                g.setColor(Color.red);
                g.fillRect(i*30+1, bricks[i].y+1, 30, 10);
            }


        }
        g.dispose();
    }


    public class ListenKeys extends KeyAdapter {
        public void keyPressed(KeyEvent e) {
            int key = e.getKeyCode();
            if (key == KeyEvent.VK_RIGHT) {
                right = true;
            }
            if (key == KeyEvent.VK_LEFT) {
                left = true;
            }
            if (key == KeyEvent.VK_R) {
                gameInit();
            }
        }

        public void keyReleased(KeyEvent e) {
            left = false;
            right = false;
        }
    }

    public class Saie extends Thread {
        public void run() {
            while (gameOn) {
                try {
                    sleep(21);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                if (right) {
                    bat.x+=5;
                }
                if (left) {
                    bat.x-=5;
                }
                if (ball.intersects(bat)) {
                    dy*=-1;
                }
                if (ball.intersects(wall_right)) {
                    dx*=-1;
                }
                if (ball.intersects(wall_left)) {
                    dx*=-1;
                }
                if (ball.intersects(wall_top)) {
                    dy*=-1;
                }
                for (int i = 0; i < bricks.length; i++) {
                    if (ball.intersects(bricks[i])) {
                        if (bricks[i].isDestroyed()) {

                        } else {
                            bricks[i].setDestroyed(true);
                            System.out.println("Brick destroyed!");
                            dy*=-1;
                            repaint();
                        }
                    }
                }
                ball.x = ball.x+dx;
                ball.y = ball.y+dy;
                repaint();
            }
        }
    }
}

Brick.java

package net.viped;

import java.awt.Rectangle;

public class Brick extends Rectangle{

    private boolean destroyed = false;

    public void setDestroyed(boolean destroyed) {
        this.destroyed = destroyed;
    }

    public boolean isDestroyed() {
        return destroyed;
    }
}

How do you execute the code for testing? I don't see a main() method.

Have you tried debugging the code by adding printlns to show the values of variables as they are changed and used?
I see one println but it doesn't show which item it is refering to. It should print out all the variables values that are being used: i and dy.

I am not sure what you mean by "i and dy". I have launch.java which is used to execute the code. It is just simple class extended from JFrame. How about those angles? By those I mean example if ball hits on the right side of the paddle ball will bounce more horizontally. Am I clear what I want? English may not be one of my best skills.

I am not sure what you mean by "i and dy".

The following code uses the variables: i & dy. Their values should be printed for debugging:

                  bricks[i].setDestroyed(true);
                  System.out.println("Brick destroyed! i="+i + ", dy="+dy);
                  dy*=-1;

if ball hits on the right side of the paddle ball will bounce more horizontally

Can you post the output from the program that shows the dx and dy values and how they change when the ball hits the paddle?

If you want help debugging the code, you need to post code with a main() that will compile, execute and show the problem.

I have changed the code little bit here is modified code for Board.java

package net.viped;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;

import javax.swing.JPanel;

public class Board extends JPanel{

    private boolean right = false;
    private boolean left = false;

    private boolean speedUp = false;
    private boolean speedDown = false;

    private boolean gameOn = false;
    private boolean gameOver = false;

    private int dy = 2;
    private int dx = 2;
    private int score = 0;
    private int speed = 20;
    private int speeds;
    Rectangle bat = new Rectangle();
    Rectangle ball = new Rectangle();
    Rectangle wall_left = new Rectangle();
    Rectangle wall_right = new Rectangle();
    Rectangle wall_top = new Rectangle();
    Brick[][] bricks = new Brick[20][5];
    Saie saie = new Saie();
    public Board() {
        addKeyListener(new ListenKeys());
        setBackground(Color.black);
        setFocusable(true);
        gameInit();
        saie.start();
    }

    public void gameOver() {
        gameOver = true;
        System.out.println("Game Over! Press r to continue");

    }

    public void gameInit() {
        bat.setBounds(100, 450, 60, 4);
        ball.setBounds(300, 200, 10, 10);
        wall_left.setBounds(0, 0, 1, 480);
        wall_right.setBounds(601, 0, 1, 480);
        wall_top.setBounds(0, 0, 600, 1);
        dy = -2;
        dx = -2;
        speed = 30;
        speeds = 1;
        for (int i = 0; i < 20; i++) {
            for (int j = 0; j < 5; j++) {
                bricks[i][j] = new Brick();
                bricks[i][j].setBounds(i*31, j*11+30, 30, 10);
            }
        }
        gameOver = false;
        gameOn = true;
    }

    public void paint(Graphics g) {
        super.paint(g);
        g.setColor(Color.green);
        g.fillRect(bat.x, bat.y, bat.width, bat.height);
        g.fillOval(ball.x, ball.y, ball.width, ball.height);

        g.setColor(Color.black);
        g.fillRect(wall_left.x, wall_left.y, wall_left.width, wall_left.height);
        g.fillRect(wall_right.x, wall_right.y, wall_right.width, wall_right.height);
        g.fillRect(wall_top.x, wall_top.y, wall_top.width, wall_top.height);
        g.setColor(Color.red);
        g.drawString("Speed: " + speeds + " Score " + score, 430, 430);
        for (int i = 0; i<20; i++) {
            for (int j = 0; j < 5; j++) {
                if (bricks[i][j].isDestroyed()) {
                    g.setColor(Color.black);
                    g.fillRect(i*30, bricks[i][j].y, bricks[i][j].width, bricks[i][j].height);
                    g.setColor(Color.black);
                    g.fillRect(i*30+1, bricks[i][j].y+1, bricks[i][j].width+1, bricks[i][j].height+1);  
                } else {
                    g.setColor(Color.black);
                    g.fillRect(i*30, bricks[i][j].y, bricks[i][j].width+2, bricks[i][j].height+2);
                    g.setColor(Color.red);
                    g.fillRect(i*30+1, bricks[i][j].y+1, bricks[i][j].width, bricks[i][j].height);
                }
            }
        }
        if (gameOver) {

            Graphics2D g2d = (Graphics2D)g;
            g2d.setFont(new Font("Arial", Font.PLAIN, 18));
            g2d.setColor(Color.red);
            g2d.drawString("Game over! \n Press r to restart", 160, 200);
        }
        g.dispose();
    }


    public class ListenKeys extends KeyAdapter {
        public void keyPressed(KeyEvent e) {
            int key = e.getKeyCode();
            if (key == KeyEvent.VK_RIGHT) {
                right = true;
            }
            if (key == KeyEvent.VK_LEFT) {
                left = true;
            }
            if (key == KeyEvent.VK_R) {
                gameOn = true;
                gameInit();
            }
            if (key == KeyEvent.VK_UP && speed > 1) {
                speed--;
                speeds++;
            }
            if (key == KeyEvent.VK_DOWN) {
                speed++;
                speeds--;
            }

        }

        public void keyReleased(KeyEvent e) {
            left = false;
            right = false;
            speedUp = false;
            speedDown = false;
        }
    }

    public class Saie extends Thread {
        public void run() {
            while (true) {
                if (gameOn) {
                    try {
                        sleep(speed);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    if (speedUp && speed > 1) {
                        speed--;
                    }
                    if (speedDown) {
                        speed++;
                    }
                    if (right) {
                        bat.x+=5;
                    }
                    if (left) {
                        bat.x-=5;
                    }
                    if (ball.intersects(bat)) {
                        dy*=-1;
                    }
                    if (ball.intersects(wall_right)) {
                        dx*=-1;
                    }
                    if (ball.intersects(wall_left)) {
                        dx*=-1;
                    }
                    if (ball.intersects(wall_top)) {
                        dy*=-1;
                    }
                    for (int i = 0; i < 20; i++) {
                        for (int j = 0; j < 5; j++) {
                            if (ball.intersects(bricks[i][j])) {
                                if (bricks[i][j].isDestroyed()) {

                                } else {
                                    dy*=-1;


                                    score++;
                                    System.out.println("Scores: " + score);
                                    repaint();
                                    bricks[i][j].setDestroyed(true);
                                }
                            }
                        }
                    }
                    if (ball.y > 450) {
                        gameOver();
                        dx = 0;
                        dy = 0;
                        ball.y = 100;
                        repaint();
                    }
                    ball.x = ball.x+dx;
                    ball.y = ball.y+dy;
                    repaint();

                }
            }
        }
    }
}

And here is the Launch.java

package net.viped;

import javax.swing.JFrame;

public class Launch extends JFrame{
    public Launch() {
        add(new Board());
        setSize(600, 480);
        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        new Launch();
    }

}

Could you point out exact line where you want the debug info. Whole programming thing is pretty new to me. Thanks for patience.

where you want the debug info

When you wrote the code you expected the variables to have certain values and for their values to change in a certain way. Debugging the code means that you should print out the values of the variables as their values change and as their values are used to control the program flow. The printed output will then show you what the computer sees and why it is doing what it is doing.

You've posted the code here because it is not doing what you want it to do. To see what it is doing, add printlns. The print out will show you where the code needs to be changed so that it will do what you want it to do.

how I should determine about which angle the ball hits to te paddle or walls or brick. And I also got weird problem. Some of bricks wont destroy after first hit of ball.

Yeah I meant from which line I should get the debug info and the problem I had earlier, the one with bricks arent destroyed, well now they are destroyed but the ball just goes straight through them. Some of them. Could you execute the code so you know what I mean. Thanks!

from which line I should get the debug info

For all variables used in the program.

I think it is not flaw with the code actually. It is when ball hits corner of the brick and it hits another bricks on the same time. How about those angles?

I think there could be a flaw in the code. Try adding printlns as I have suggested.

What angle are you talking about? Add printlns to the code to print out the values of ball's location and copy and paste the print out here with comments showing what the problem is with where the ball is moving to.

On first hit to bricks the ball destroys three bricks at once, here is balls getBounds() (this is the one you wanted?)
java.awt.Rectangle[x=182,y=82,width=10,height=10]
java.awt.Rectangle[x=182,y=82,width=10,height=10]
java.awt.Rectangle[x=172,y=72,width=10,height=10]

And about the angles, the code works as I have coded it. The angle thing is feature that I have'nt programmed yet and don't know how to. Now when the ball hits the paddle it changes direction

dy*=-1

so if it comes from up left it leaves paddle up right. What I want is that it leaves paddle more right than up that much as it hits right side of the paddle.

I want is that it leaves paddle more right than up that much as it hits right side of the paddle.

Are you talking about when the ball hits the ends of the paddle vs hitting the top of the paddle?
What does that mean for the values of dx and dy? To the right is +x, up is -y

The print outs you posted shows that the position did not change from the first to the second print out and then moved up 10 for the third print out.
You have not printed out enough data to say what is happening. You need to printout everything involved with the event: i, j, bricks[i][j], ball, dy

Here is the dy:s also printed, those show that it changes direction after hit. So it should move. I think it is just that those 2 bricks are 1 or more px overlapped and it really hits them both.

dy before: -2
dy after: 2
ball.getBounds(): java.awt.Rectangle[x=182,y=82,width=10,height=10]
dy before: 2
dy after: -2
ball.getBounds(): java.awt.Rectangle[x=182,y=82,width=10,height=10]
dy before: -2
dy after: 2
ball.getBounds(): java.awt.Rectangle[x=172,y=72,width=10,height=10]

Yes that I meant with angles. I know I should grow dx to get it more right but I don't know how to determine where the ball hits.

Edit. ((float)ball.x/(float)bat.x) does the trick.

Your print out does not show where the bricks are. Try putting more items on one line to make it easier to see what is changing from one event/collision to the next. You don't have to print the before AND after for dy. It will always be the opposite sign.

how to determine where the ball hits.

Are you looking for the x,y and width,height for where the two objects touch when there is a collision?
Given the positions of the two objects you should be able to compute where the ball hits where there is a collision. You know the x,y and width and height for both.

those 2 bricks are 1 or more px overlapped and it really hits them both.

Two can be hit at the same time, so your code must allow for that.

Here is new Board.java and it atleast looks like working, with angles and all. Thanks for your help!

package net.viped;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;

import javax.swing.JPanel;

public class Board extends JPanel{

    private boolean right = false;
    private boolean left = false;

    private boolean speedUp = false;
    private boolean speedDown = false;

    private boolean gameOn = false;
    private boolean gameOver = false;

    private float dy = 2;
    private float dx = 2;
    private int score = 0;
    private int speed = 20;
    private int speeds;

    private boolean c = false;
    private boolean h = false;

    private int bat_width = 60;

    Rectangle bat = new Rectangle();
    Rectangle ball = new Rectangle();
    Rectangle wall_left = new Rectangle();
    Rectangle wall_right = new Rectangle();
    Rectangle wall_top = new Rectangle();
    Brick[][] bricks = new Brick[20][5];
    Saie saie = new Saie();
    public Board() {
        addKeyListener(new ListenKeys());
        setBackground(Color.black);
        setFocusable(true);
        gameInit();
        saie.start();
    }

    public void gameOver() {
        gameOver = true;

    }

    public void gameInit() {
        bat_width = 60;
        bat.setBounds(100, 450, bat_width, 4);
        ball.setBounds(300, 200, 10, 10);
        wall_left.setBounds(0, 0, 1, 600);
        wall_right.setBounds(601, 0, 1, 600);
        wall_top.setBounds(0, 0, 600, 1);
        dy = -2;
        dx = -2;
        speed = 30;
        speeds = 1;
        score = 0;
        for (int i = 0; i < 20; i++) {
            for (int j = 0; j < 5; j++) {
                bricks[i][j] = new Brick();
                bricks[i][j].setBounds(i*31, j*11+30, 27, 10);
            }
        }
        gameOver = false;
        gameOn = true;
    }

    public void paint(Graphics g) {
        super.paint(g);
        g.setColor(Color.green);
        g.fillRect(bat.x, bat.y, bat.width, bat.height);


        g.setColor(Color.black);
        g.fillRect(wall_left.x, wall_left.y, wall_left.width, wall_left.height);
        g.fillRect(wall_right.x, wall_right.y, wall_right.width, wall_right.height);
        g.fillRect(wall_top.x, wall_top.y, wall_top.width, wall_top.height);
        g.setColor(Color.red);
        g.drawString("Speed: " + speeds + " Score " + score, 430, 430);
        for (int i = 0; i<20; i++) {
            for (int j = 0; j < 5; j++) {
                if (bricks[i][j].isDestroyed()) {
                    g.setColor(Color.black);
                    g.fillRect(i*30, bricks[i][j].y, bricks[i][j].width, bricks[i][j].height);
                    g.setColor(Color.black);
                    g.fillRect(i*30+1, bricks[i][j].y+1, bricks[i][j].width+1, bricks[i][j].height+1);  
                } else {
                    g.setColor(Color.black);
                    g.fillRect(i*30, bricks[i][j].y, bricks[i][j].width+2, bricks[i][j].height+2);
                    g.setColor(Color.red);
                    g.fillRect(i*30+1, bricks[i][j].y+1, bricks[i][j].width, bricks[i][j].height);
                }
            }
        }
        g.setColor(Color.green);
        g.fillOval(ball.x, ball.y, ball.width, ball.height);
        if (gameOver) {

            Graphics2D g2d = (Graphics2D)g;
            g2d.setFont(new Font("Arial", Font.PLAIN, 18));
            g2d.setColor(Color.red);
            g2d.drawString("Game over! \n Press r to restart", 160, 200);
        }
        if (score == 100) {
            Graphics2D g2d = (Graphics2D)g;
            g2d.setFont(new Font("Arial", Font.PLAIN, 18));
            g2d.setColor(Color.red);
            g2d.drawString("You won! \n Press r to restart", 160, 200);
        }
        g.dispose();
    }


    public class ListenKeys extends KeyAdapter {
        public void keyPressed(KeyEvent e) {
            int key = e.getKeyCode();
            if (key == KeyEvent.VK_RIGHT) {
                right = true;
            }
            if (key == KeyEvent.VK_LEFT) {
                left = true;
            }
            if (key == KeyEvent.VK_R) {
                gameOn = true;
                gameInit();
            }
            if (key == KeyEvent.VK_UP && speed > 1) {
                speed--;
                speeds++;
            }
            if (key == KeyEvent.VK_DOWN) {
                speed++;
                speeds--;
            }
            if (key == KeyEvent.VK_C) {
                c = true;
            }
            if (key == KeyEvent.VK_H) {
                h = true;
            }

        }

        public void keyReleased(KeyEvent e) {
            left = false;
            right = false;
            speedUp = false;
            speedDown = false;
            c = false;
            h = false;
        }
    }

    public class Saie extends Thread {
        public void run() {
            while (true) {
                if (gameOn) {
                    try {
                        sleep(speed);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    if (c == true && h == true) {
                        bat.width = 600;
                    }
                    if (right) {
                        bat.x+=5;
                    }
                    if (left) {
                        bat.x-=5;
                    }
                    if (ball.intersects(bat)) {
                        float angle = ((float)ball.x/(float)bat.x);
                        if (angle > 1 && angle < 20) {
                            dy*=-1;
                            dx=3*angle;
                        }
                        else if (angle < 1 && angle > -20) {
                            dy*=-1;
                            dx=3*-angle;
                        } else {
                            dy*=-1;
                        }

                    }
                    if (ball.intersects(wall_right)) {

                        dx*=-1;
                    }
                    if (ball.intersects(wall_left)) {
                        dx*=-1;
                    }
                    if (ball.intersects(wall_top)) {
                        dy*=-1;
                    }
                    for (int i = 0; i < 20; i++) {
                        for (int j = 0; j < 5; j++) {
                            if (ball.intersects(bricks[i][j])) {
                                if (bricks[i][j].isDestroyed()) {

                                } else {
                                    dy*=-1;
                                    score++;

                                    bricks[i][j].setDestroyed(true);
                                    int special = (int) (10*Math.random());
                                    if (special == 1) {
                                        bat.width+=10;
                                    }
                                    repaint();
                                }
                            }
                        }
                    }
                    if (ball.y > 450) {
                        gameOver();
                        dx = 0;
                        dy = 0;
                        ball.y = 100;
                        repaint();
                    }
                    ball.x = (int) (ball.x+dx);
                    ball.y = (int) (ball.y+dy);
                    repaint();

                }
            }
        }
    }
}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.