1

Is this the right site to ask this question, since I've been referred to another site two times by now.

I'm trying to create bouncing balls with realistic physics. At the moment, when the balls hit each other, they bounce back in the same direction they were coming from, now, I've searched the internet for how to do this, but I only find things about how to detect collision, not what to do after. I don't know a lot about physics, are their topics I should learn first before I would be able to do this? Here's an image of how I imagine balls would bounce in real life. Is this how it works?

how I think it should work
(source: thewombatguru.nl)

Also, do I have bad practises in my code? (probably, but I'm learning a lot and I like it)

This is my current code:

Asteroids.java

package Asteroids;

import javax.swing.*;

public class Asteroids {

    public static void createAndShowGui() {
        GamePanel gamePanel = new GamePanel();
        JFrame frame = new JFrame("Asteroids");
        frame.getContentPane().add(gamePanel);
        frame.pack();
        frame.setVisible(true);
        frame.setResizable(false);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setLocation(2000, 50);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }

}

GamePanel.java

package Asteroids;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

public class GamePanel extends JPanel implements ActionListener {

    private final int WIDTH = 1000;
    private final int HEIGHT = 1000;

    Timer animationTimer;

    ArrayList<Rock> rocks;

    public GamePanel() {
        Dimension preferredDimension = new Dimension(WIDTH, HEIGHT);
        setPreferredSize(preferredDimension);

        animationTimer = new Timer(10, this);

        setUp();
    }

    public void setUp() {

        rocks = new ArrayList<>();

        rocks.add(new Rock(475, 1000, 0, -1));
        rocks.add(new Rock(0, 500, 1, 0));
        //rocks.add(new Rock(300, 270, -2, 2));
        //rocks.add(new Rock(400, 315, -5, -1));

        animationTimer.start();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        repaint();

        for (Rock rock : rocks) {
            for (Rock rockToCheck : rocks) {
                if (!rock.equals(rockToCheck)) {
                    rock.checkForCollisionWithRocks(rockToCheck);
                }
            }
            rock.checkForCollisionWithFrame(WIDTH, HEIGHT);
            rock.setxPos(rock.getxPos() + rock.getxVelocity());
            rock.setyPos(rock.getyPos() + rock.getyVelocity());
        }
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        Graphics2D g2d = (Graphics2D) g.create();

        RenderingHints mainRenderingHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHints(mainRenderingHints);

        for (Rock rock : rocks) {
            rock.display(g2d);
        }

        g2d.dispose();
    }
}

Rock.java

package Asteroids;

import java.awt.*;

public class Rock {

    private int xPos;
    private int yPos;
    private int rockWidth;
    private int rockHeight;
    private int xVelocity;
    private int yVelocity;
    private int rockRadius;
    private Color rockColor;

    public Rock(int xPos, int yPos, int xVelocity, int yVelocity) {
        this.xPos = xPos;
        this.yPos = yPos;
        this.xVelocity = xVelocity;
        this.yVelocity = yVelocity;
        rockWidth = 50;
        rockHeight = rockWidth;
        rockRadius = rockWidth / 2;
        rockColor = new Color((int) (Math.random() * 255),(int) (Math.random() * 255),(int) (Math.random() * 255));
    }

    public void setxPos(int xPos) {
        this.xPos = xPos;
    }
    public int getxPos() {
        return xPos;
    }
    public int getRockWidth() {
        return rockWidth;
    }
    public void setRockWidth(int rockWidth) {
        this.rockWidth = rockWidth;
    }
    public int getRockHeight() {
        return rockHeight;
    }
    public void setRockHeight(int rockHeight) {
        this.rockHeight = rockHeight;
    }
    public int getyPos() {
        return yPos;
    }
    public void setyPos(int yPos) {
        this.yPos = yPos;
    }
    public int getxVelocity() {
        return xVelocity;
    }
    public void setxVelocity(int xVelocity) {
        this.xVelocity = xVelocity;
    }
    public int getyVelocity() {
        return yVelocity;
    }
    public void setyVelocity(int yVelocity) {
        this.yVelocity = yVelocity;
    }
    public int getRockRadius() {
        return rockRadius;
    }
    public void setRockRadius(int rockRadius) {
        this.rockRadius = rockRadius;
    }

    public void checkForCollisionWithRocks(Rock rock) {
        int radiusOfBoth = rock.getRockRadius() + rockRadius;
        int horDistance = Math.abs((rock.getxPos() + rock.getRockRadius()) - (xPos + rockRadius));
        int verDistance = Math.abs((rock.getyPos() + rock.getRockRadius()) - (yPos + rockRadius));
        int diagDistance = (int) Math.sqrt(Math.pow(horDistance, 2) + Math.pow(verDistance, 2));

        if (diagDistance <= radiusOfBoth) {

            xVelocity = -xVelocity;
            yVelocity = -yVelocity;

            rock.setxVelocity(-rock.getxVelocity());
            rock.setyVelocity(-rock.getyVelocity());
            rock.setxPos(rock.getxPos() + rock.getxVelocity());
            rock.setyPos(rock.getyPos() + rock.getyVelocity());
        }
    }

    public void checkForCollisionWithFrame(final int WIDTH, final int HEIGHT) {
        if (xPos < 0) {
            xVelocity *= -1;
            xPos = 0;
        } else if (xPos + rockWidth > WIDTH) {
            xVelocity *= -1;
            xPos = WIDTH - rockWidth;
        }

        if (yPos < 0) {
            yVelocity *= -1;
            yPos = 0;
        } else if (yPos + rockHeight > HEIGHT) {
            yVelocity *= -1;
            yPos = HEIGHT - rockHeight;
        }
    }

    public void display(Graphics2D g2d) {
        g2d.setColor(rockColor);
        g2d.fillOval(xPos, yPos, rockWidth, rockHeight);
    }

}

Can anyone help ?

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
The Coding Wombat
  • 805
  • 1
  • 10
  • 29
  • If by *what happens after* you mean the velocity (speed + direction) of each component, I think you ought to read a little bit about elastic collisions. You could ask [physics.stackexchange.com](http://physics.stackexchange.com/) for some mathematical models I think it is worth mentioning some background, since this can get pretty complex pretty fast. Lastly, for code reviews, please rever to [codereview.stackexchange.com](http://codereview.stackexchange.com/). – npinti May 18 '15 at 11:42
  • @npinti Yes, I meant speed and direction, but I want to start with only direction, because all my balls move at the same speed, and I don't want them to "lose energy" once they hit something. I'll do some reading on elastic collisions. And codereview sent me here – The Coding Wombat May 18 '15 at 11:44
  • I think this would be a good read unless you already have digested it: http://en.wikipedia.org/wiki/Elastic_collision#Two-Dimensional_Collision_With_Two_Moving_Objects – laune May 18 '15 at 11:47
  • @laune Thanks, I'm currently reading about elastic collisions yes. – The Coding Wombat May 18 '15 at 11:48
  • The direction will determine on the angle of impact to say the least, you would then need to split the force if the impact into components (vertical and horizontal). You would then work out the forces and take it from there. – npinti May 18 '15 at 11:48
  • Also consider the vector approach cited [here](http://stackoverflow.com/a/12041004/230513). – trashgod May 18 '15 at 12:12

3 Answers3

2

You can start with the law of conservation of momentum. When two objects collide the total momentum will not change, you can use this link to understand the calculations behind while trying to predict the trajectories of two objects after they collide.

As for your code, you seem to be missing a crucial field mass in your Rock.java. You need mass in order to calculate the momentum of an object which later you will use to predict the trajectories after the objects collide.

EDIT: Note that the examples in the link are somewhat limited to 2 directions where the objects collide against each other with 180* between them. However it is not that hard to generalize and find the velocity of an object after the collision by breaking down the momentum/velocity vectors to 4 directions, that are 0,90,180,270 degrees. You have to use vector math to express the speed of a given object in terms of the 4 directions.

Community
  • 1
  • 1
Berkay Dincer
  • 112
  • 1
  • 10
  • Thank you, I'll do some reading on that topic. I currently don't have in mind to add rocks with different masses, so I figure that I can just replace the m in all equations by a 1? – The Coding Wombat May 18 '15 at 11:53
  • Sure you can do that, if the masses are same equation gets much more simpler (notice the masses cancel each other on the both sides of the equation). Also see my edit :) – Berkay Dincer May 18 '15 at 11:56
1

Real life physics is tricky (gravity, inertia, etc), but to start with, bouncing the balls off of each other:

When the two balls hit, there's an angle of collision. Luckily, because they are circles (assuming) you can find the angle of incidence by finding the angle of the line going through the center of the two balls. Then you want to send 1 ball off 1 way perpendicular the that line, and the other the other way.

Make sense?

ControlAltDel
  • 33,923
  • 10
  • 53
  • 80
  • Yes, thanks, this is going to help me, a perpendicular line makes sense (even though I hadn't seen the word perpendicular ever before, but now I know what it is) – The Coding Wombat May 18 '15 at 11:47
  • I accept the answer for now :) I think I will figure it out, if not, I'll continue asking. – The Coding Wombat May 18 '15 at 11:58
  • What if I just were to switch the current x and yvelocity values of the two balls bouncing off each other, that would be kind of realistic right? int tempXVelocity = this.xVelocity; int tempYVelocity = this.yVelocity; this.xVelocity = rock.xVelocity; this.yVelocity = rock.yVelocity; rock.xVelocity = tempXVelocity; rock.yVelocity = tempYVelocity; – The Coding Wombat May 18 '15 at 17:52
0

Answer here: Also there is a nice gif,you can easily find out,how to calculate the new velocities ;) Ball to Ball Collision - Detection and Handling

Community
  • 1
  • 1