Search code examples
javacollision-detectionacm-java-libraries

Java Glitchy Collision Detection with ACM Graphics


I'm quite new to Java and I am using the ACM library for graphics. What I'm trying to do with this code is to:

  1. Introduce two balls, one on the left side and one in the middle. Both of them are in the middle, y coordinate-wise.
  2. Make the first ball move until meeting the second ball. Then stop and give the second ball a velocity proportional to its size (resembling a conservation of momentum).
  3. Make the second ball bounce of the wall, and move until meeting the first ball. Then stop and give the first ball a velocity proportional to its size once again.
  4. Make this action infinite.

My code is as such:

import java.awt.Color;

import acm.graphics.*;
import acm.program.*;
import acm.util.RandomGenerator;

public class Collision extends GraphicsProgram {

    private static final double RADIUS_ONE = 35;
    private static final double RADIUS_TWO = 65; 

    public void run() {

        GOval ballOne = new GOval(0, (getHeight() - RADIUS_ONE)/2, RADIUS_ONE, RADIUS_ONE);
        ballOne.setFilled(true);
        ballOne.setColor(Color.GREEN);
        add(ballOne);

        GOval ballTwo = new GOval((getWidth() - RADIUS_TWO)/2, (getHeight() - RADIUS_TWO)/2, RADIUS_TWO, RADIUS_TWO);
        ballTwo.setFilled(true);
        ballTwo.setColor(Color.ORANGE);
        add(ballTwo);

        double velocityOne = 3;
        double velocityTwo = 0;

        while (true) {  

            ballOne.move(velocityOne, 0);
            ballTwo.move(velocityTwo, 0);

            if (ballOne.getX() >= getWidth() - RADIUS_ONE || ballOne.getX() <= 0) {
                velocityOne = -velocityOne;
            }
            if (ballTwo.getX() >= getWidth() - RADIUS_TWO || ballTwo.getX() <= 0) {
                velocityTwo = -velocityTwo;
            }

            if (ballOne.getX() + RADIUS_ONE >= ballTwo.getX()) {

                if (velocityTwo == 0) {
                    velocityTwo = (velocityOne * RADIUS_ONE * RADIUS_ONE)/(RADIUS_TWO * RADIUS_TWO);
                    velocityOne = 0;
                } else if (velocityOne == 0) {
                    velocityOne = (velocityTwo * RADIUS_TWO * RADIUS_TWO)/(RADIUS_ONE * RADIUS_ONE);
                    velocityTwo = 0;
                }

            }

            pause(10);
        }
    }
}

If you run this code, you'll see it malfunctions. Upon meeting the second ball, the first ball doesn't stop moving and moves along with the second ball. But if you change velocityOne to 2 instead of 3, it works all fine. Or if you RADIUS_TWO to 45 instead of 65, the code functions as it should for every value of velocityOne.

Could anybody explain me why this code is malfunctioning for most values, while working as it is supposed to with so little? Thanks a lot.


Solution

  • When it comes to detecting collisions, you're going to run into a lot of bugs! It's a very common thing.

    The reason you're getting these errors is because when you're trying to detect collisions, your code is refreshing every interval (you can usually choose the time between intervals) and checking to see if two things are intersecting yet. In this case, I'm assuming that your ball is going right past the other one too fast for your "collision checker" to pick it up.

    A few things you can do:

    -Slow the ball down

    -Decrease the time between "checks for collision"

    -Increase the collision area (this means that even if the checker doesn't see the edges collide, if the two areas are overlapping, it know they've collided already)