Click here to Skip to main content
15,888,579 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am working on a 4 Way Pong Program. I have it to the point where my paddles will move with mouse movement, and the ball will bounce around the screen.

I am stuck when it comes to figuring out how to check for collisions between the ball and the paddles (which will increase the score) and between the ball and the edges of the JPanel (which will end the game).

Any guidance is greatly appreciated...

Game Class

Java
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Game extends JPanel {

    JFrame window = new JFrame();
    Timer timer = new Timer(30, new ActionHandler());
    ArrayList<Ball> balls = new ArrayList<Ball>();
    ArrayList<Paddle> horizPaddles = new ArrayList<Paddle>();
    ArrayList<Paddle> vertPaddles = new ArrayList<Paddle>();
    Paddle pTop;
    Paddle pBottom;
    Paddle pRight;
    Paddle pLeft;
    Ball b;
    int score = 0;
    JLabel scoreLabel;

    //==========================================================
    public Game() {

        window.setBounds(100,100,900,500);
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setTitle("4 Way Pong");
        window.setResizable(false);

        JPanel scorePanel = new JPanel(true);

        scoreLabel = new JLabel("Current Score: " + Integer.toString(score));
        scoreLabel.setFont(new Font("sansserif", Font.PLAIN, 20));
        scoreLabel.setForeground(Color.RED);
        scorePanel.add(scoreLabel);

        JPanel buttons = new JPanel(true);

        Container con = window.getContentPane();    
        con.setLayout(new BorderLayout());
        con.add(this, BorderLayout.CENTER);
        con.add(buttons, BorderLayout.SOUTH);
        con.add(scorePanel, BorderLayout.NORTH);

        this.setBackground(Color.BLACK);
        this.addMouseMotionListener(new MouseMoved());

        ButtonCatch bc = new ButtonCatch();

        JButton btn;
        btn = new JButton("New Game");
        btn.addActionListener(bc);
        buttons.add(btn); 

        btn = new JButton("Swap Colors");
        btn.addActionListener(bc);
        buttons.add(btn); 

        btn = new JButton("High Scores");
        btn.addActionListener(bc);
        buttons.add(btn); 

        btn = new JButton("Save Score");
        btn.addActionListener(bc);
        buttons.add(btn); 

        btn = new JButton("Quit");
        btn.addActionListener(bc);
        buttons.add(btn); 

        timer.start();

        window.setVisible(true);
    }

    //==========================================================
    public static void main(String[] args) {             
        new Game();
    }

    //==========================================================
    public void update() {
        for(Ball b : balls) {
            b.move(getWidth() + 30, getHeight() + 25);
        }


        //checkSideCollision();
        //checkHorizPaddleCollision();
        //checkVertPaddleCollision();
        repaint();
    }

    //==========================================================
    public void checkSideCollision() {
        if(b.getyPos() > getHeight()) {
            JOptionPane.showMessageDialog(null, "Game Over.  You Scored " + score + ".", "GAME OVER", JOptionPane.INFORMATION_MESSAGE);
            System.exit(0);
        }
    }

    //==========================================================
    public void checkHorizPaddleCollision() {
        if(b.getxPos() == pBottom.getX() && b.getyPos() == pBottom.getY()) {
            //b.yPos = b.yPos - 5;
            score++;
        }
    }

    //==========================================================
    public void checkVertPaddleCollision() {

    }

    //==========================================================
    public class ButtonCatch implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            switch(e.getActionCommand()) {
            case "Quit":        JOptionPane.showMessageDialog(null, "You Quit... No Score Recorded", "Game Over", JOptionPane.INFORMATION_MESSAGE); System.exit(0);
            case "New Game":    newGame(); break;
            case "Swap Colors": swapColors(); break;
            case "High Scores": try { displayScores(); } catch (Exception e1) { System.out.println(e1.getMessage()); } break;
            case "Save Score":   try { saveScore(); } catch (Exception e2) { System.out.println(e2.getMessage()); } break;
            }
        }   
    }

    //==========================================================
    public void paint(Graphics g) {
        super.paint(g);

        for(Ball b : balls) {
            b.draw(g);
        }

        for(Paddle p : horizPaddles) {
            p.draw((Graphics2D) g);
        }

        for(Paddle p : vertPaddles) {
            p.draw((Graphics2D) g);
        }
    }

    //==========================================================
    //FIX FOR DISPLAYING SCORES
    private void displayScores() throws Exception { 

    }

    //==========================================================
    //FIX -- Store Score in a File
    private void saveScore() throws Exception {
        int userScore = score;
        String name = JOptionPane.showInputDialog("Enter Your Name: ");
        JOptionPane.showMessageDialog(null, "Saved!\n" + name + " scored " + userScore, "Score Recorded", JOptionPane.INFORMATION_MESSAGE);
    }

    //==========================================================
    private void swapColors() {
        for(Ball b : balls) {
            if(b.color.equals(Color.red)) { 
                b.setColor(Color.yellow);
            } else if (b.color.equals(Color.yellow)) {
                b.setColor(Color.blue);
            } else {
                b.setColor(Color.red);
            }
        }
    }

    //==========================================================
    private void newGame() {
        //CREATE BALL
        balls.clear();

        b = new Ball();
        b.color = Color.red;
        b.dx = (int)(Math.random() * 4) + 1;
        b.dy = (int)(Math.random() * 4) + 1;
        b.xPos = (int)(Math.random() * 4) + 1;
        b.yPos = (int)(Math.random() * 4) + 1;

        balls.add(b);

        //CREATE PADDLES
        horizPaddles.clear();
        vertPaddles.clear();

            // bottom
        pBottom = new Paddle();
        pBottom.x = getWidth() / 2;
        pBottom.y = getHeight();
        pBottom.setX(pBottom.getX()-20);
        pBottom.setY(pBottom.getY()-20);
        pBottom.setWidth(100);
        pBottom.setHeight(20);
        horizPaddles.add(pBottom);

            //top
        pTop = new Paddle();
        pTop.x = getWidth() / 2;
        pTop.y = getHeight();
        pTop.setX(0 + pTop.getX());
        pTop.setY(0);
        pTop.setWidth(100);
        pTop.setHeight(20);
        horizPaddles.add(pTop);

            //left
        pLeft = new Paddle();
        pLeft.x = getWidth() / 2;
        pLeft.y = getHeight();
        pLeft.setX(0);
        pLeft.setY(pLeft.getY() / 2);
        pLeft.setWidth(20);
        pLeft.setHeight(100);
        vertPaddles.add(pLeft);

            //right
        pRight = new Paddle();
        pRight.x = getWidth() / 2;
        pRight.y = getHeight();
        pRight.setX(875);
        pRight.setY(pRight.getY() / 2);
        pRight.setWidth(20);
        pRight.setHeight(100);
        vertPaddles.add(pRight);

        timer.start();

    }

    //==========================================================
    public class ActionHandler implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent arg0) {
            update();
        }

    }

    //==========================================================
    public class MouseMoved implements MouseMotionListener {

        @Override 
        public void mouseMoved(MouseEvent e) {
            for(Paddle p : horizPaddles) {
                p.x = e.getX();
            }

            for(Paddle p : vertPaddles) {
                p.y = e.getY();
            }
        }

        @Override public void mouseDragged(MouseEvent e) {}

    }

}


Paddle Class

Java
import java.awt.Color;
import java.awt.Graphics2D;

public class Paddle implements Drawable{
    public int x, y, width, height;

    public Paddle() {
        super();
    }

    public Paddle(int x, int y, int width, int height) {
        super();
        setX(x);
        setY(y);
        setWidth(width);
        setHeight(height);
    }

    @Override
    public void draw(Graphics2D g) {
        g.setColor(Color.green);
        g.fillRect(x, y, width, height);
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

}


Ball Class

Java
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.io.IOException;
import java.io.RandomAccessFile;

import javax.swing.JPanel;

public class Ball implements Comparable<Ball>, Cloneable{
    private static int count = 0;
    public static final int NAME_LENGTH = 20;
    public String name = "";
    public int xPos=0, yPos=0, dx = 3, dy = 2;
    public Color color = Color.red;

    public static void resetCounter() { count = 0; }

    public Ball() {name = "Rock: " + ++count;}

    public Ball(RandomAccessFile file) {
        load(file);
    }

    public void load(RandomAccessFile file) {
        try {
            xPos = file.readInt();
            yPos = file.readInt();
            dx = file.readInt();
            dy = file.readInt();
            color = new Color( file.readInt() );

            byte[] n = new byte[NAME_LENGTH];
            file.readFully(n);
            name = new String(n).trim();
            System.out.println(name);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void save(RandomAccessFile file) {
        try {
            file.writeInt(xPos);
            file.writeInt(yPos);
            file.writeInt(dx);
            file.writeInt(dy);
            file.writeInt(color.getRGB());
            file.writeBytes( getStringBlock(name, NAME_LENGTH) );

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private String getStringBlock(String string, int len) {
        StringBuilder sb = new StringBuilder(name);
        sb.setLength(len);
        return sb.toString();       
    }


    public void draw(Graphics g) {
        g.setColor(color);
        g.fillOval(xPos, yPos, 25, 25);
        g.setColor(Color.black);
        g.drawOval(xPos, yPos, 25, 25);
    }

    public void setColor(Color c) {
        color = c;
    }

    public void move(int width, int height) {
        xPos+=dx;
        yPos+=dy;

        if(xPos + 50 > width) {
            xPos = width - 50;
            dx = -dx;
        } 

        if(yPos + 50 > height) {
            yPos = height - 50;
            dy = -dy;
        } 

        if(xPos < 0) {
            xPos = 0;
            dx = -dx;
        }

        if(yPos < 0) {
            yPos = 0;
            dy = -dy;
        }
    }

    @Override
    public int compareTo(Ball arg0) {

        return 0;
    }

    public int getxPos() {
        return xPos;
    }

    public int getyPos() {
        return yPos;
    }

}


Thanks again in advance for any help!
Posted

1 solution

caveat - I haven't looked at your code:

Normally you would deal with a bounding box for each item you want to test for collision - assuming your paddles are relatively rectangular, then the bounding box for each should be simple to determine.

For the ball, presumably circular, the bounding box is a square, of side = diameter of ball, centered at the ball's centre. Again, simple to determine.

Now, as there are four bats and one ball, I would have your paddle class check for a collision with the ball (assuming the paddles don't collide with one another)

Collisions occur when a point in one bounding box is inside the other, so for the paddle

let its bottom left corner be at Xp, Yp and it has a width of Wp and height of Hp

The ball is bottom left corner Xb, Yb and width height at Wb, Hb

Your collision check would be something like...

If (Xp > (Xb + Wb)) return false; // Paddle is entirely to the right of the ball
If ((Xp + Wp) < Xb) return false; // Paddle is entirely to the left of the ball

...

and so on

Collision with the edges can be done similarly - i.e. use the same principal, but checking that the ball is within the bounding box of the screen, rather than outside it.

One thing with collisions is that you need to allow for tunneling; this is where, the granularity of your simulation means that in one frame the ball is, say, one pixel infront of the bat, and in the next it is one pixel (say) behind the bat (e.g. your ball is travelling at 10 pixels per frame and your bat is 2 pixels wide and the ball is 6 pixels per frame)

This is also a problem when the ball doesn't pass right through the paddle; The ball may bounce, but immediately (next frame) it is still touching the paddle. You can use a timer of some sort to avoid this (only collide once per x frames of animation)
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
Top Experts
Last 24hrsThis month


CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900