Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Collision Detection using bounded boxes

I'm doing a programing project for class. We are programing the game break out, which consist of a ball, a paddle, four edges, and bricks. the ball bounces off the different objects and each object preforms different operations upon itself when a collision is detected. below is my code which currently doesn't work. I'm trying to use the location of the object (its center point) to construct a bounded box and the values of each edge(Top, Bottom, Left, Right) to calculate if the boxes hit. I figured in my head that there could be two types of collisions one where the corners hit and one where one object hits somewhere in the middle of the other object. Please look over my code and help if you can. I don't know if there is a better way to do what I'm trying to do but what I have currently doesn't work and returns a value of true pretty much all the time.

This is the part of the code that checks every object that is able to collide with every other object that can collide. it also moves each object and ticks the game's clock.

/**
     * Tell the GameWorld that the "game clock" has ticked. A clock tick in the GameWorld has the 
     * following effects: (1) all movable objects are told to update their positions according to there 
     * current heading and speed, (2) the "elapsed game time" is incremented by one and (3) all Items are 
     * checked for a collision.
     */
    public void tickClock() {
        gameClock++;
        Iterator theElements0 = listOfGameObjects.getIterator();
        while (theElements0.hasNext()){
            GameObject gObj = (GameObject) theElements0.getNext();
            if ( gObj instanceof IMovable){
                IMovable mObj = (IMovable)gObj;
                mObj.move(gameClock);
            }
        }
        Iterator theElements1 = listOfGameObjects.getIterator();
        while (theElements1.hasNext()){
            GameObject gObj0 = theElements1.getNext();//get a collidable object.
            if(gObj0 instanceof ICollider){
                ICollider curObj = (ICollider) gObj0;
                //check if this object collides with any OTHER object.
                Iterator theElements2 = listOfGameObjects.getIterator();
                while(theElements2.hasNext()){
                    GameObject gObj1 = theElements2.getNext();
                    if(gObj1 != curObj && gObj1 instanceof ICollider) {
                        ICollider otherObj = (ICollider) gObj1;
                        if (curObj.collidesWith(otherObj)){
                            curObj.handleCollision(otherObj);
                        }
                    }
                }   
            }
        }
        setChanged();
        notifyObservers();
    }

This is the part of the code that is used to determine if an object has collided with another object and also the appropriate action to take if it has. This section of code is from the ball object specifically, so the action preformed when it hits a brick is the ySpeed is reversed.

public boolean collidesWith(ICollider otherObj) {
        GameObject gObj = (GameObject) otherObj;
        //this collider
        int r1 = (int) (getX() + getWidth()/2);
        int l1 = (int) (getX() - getWidth()/2);
        int t1 = (int) (getY() + getHeight()/2);
        int b1 = (int) (getY() - getHeight()/2);

        //the other collider
        int r2 = (int) (gObj.getX() + gObj.getWidth()/2);
        int l2 = (int) (gObj.getX() - gObj.getWidth()/2);
        int t2 = (int) (gObj.getY() + gObj.getHeight()/2);
        int b2 = (int) (gObj.getY() - gObj.getHeight()/2);

        //corner collision check
        if(r1>l2 && t2>b1 && t1>t2 && b1>b2){
            System.out.println("Corner Collision check 1");
            return true;
        }
        if(r2>l1 && t2>b1 && t1>t2 && b1>b2){
            System.out.println("Corner Collision check 2");
            return true;
        }
        if(r2>l1 && t1>b2 && t2>t1 && b2>b1){
            System.out.println("Corner Collision check 3");
            return true;
        }
        if(r1>l2 && t1>b2 && t2>t1 && b2>b1){
            System.out.println("Corner Collision check 4");
            return true;
        }

        //middle collision check
        if(l1>l2 && r1<r2 && t1<t2 && b1<b2){
            System.out.println("middle collision check 1");
            return true;
        }
        if(l1>l2 && r1<r2 && t1>t2 && b1>b2){
            System.out.println("middle Collision check 2");
            return true;
        }
        if(l1<l2 && r1<r2 && t1<t2 && b1>b2){
            System.out.println("middle Collision check 3");
            return true;
        }
        if(l1>l2 && r1>r2 && t1<t2 && b1>b2){
            return true;
        }

        return false;
    }

    public void handleCollision(ICollider otherObject) {
        if(otherObject instanceof Brick){
            System.out.println("Brick Hit");
            ySpeed = -(ySpeed);
        }
    }
like image 564
T. Thomas Avatar asked Jan 17 '23 21:01

T. Thomas


1 Answers

You only need to check the edges of the bounding box. Some pseudo code could look like.

if Rect1[RIGHT] < Rect2[LEFT] or
   Rect1[LEFT] > Rect2[RIGHT] or
   Rect1[TOP] < Rect2[BOTTOM] or
   Rect1[BOTTOM] > Rect2[TOP]
then return false
else return true

What this is trying to say is that if there are any possible gaps along the X or Y coordinate system separating the boxes then a collision is not possible. This is a very simple version of the SAT (Separating Axis Theorem)

A little image of what this looks like visually, the same idea is applied here also.

Visualisation of SAT

This should mean that something similar to the following should work. Please note I haven't testing it but could lead you in the right direction.

public boolean collidesWith(ICollider otherObj) {
    GameObject gObj = (GameObject) otherObj;
    //this collider
    int r1 = (int) (getX() + getWidth()/2);
    int l1 = (int) (getX() - getWidth()/2);
    int t1 = (int) (getY() + getHeight()/2);
    int b1 = (int) (getY() - getHeight()/2);

    //the other collider
    int r2 = (int) (gObj.getX() + gObj.getWidth()/2);
    int l2 = (int) (gObj.getX() - gObj.getWidth()/2);
    int t2 = (int) (gObj.getY() + gObj.getHeight()/2);
    int b2 = (int) (gObj.getY() - gObj.getHeight()/2);

    if (r1 < l2 || l1 > r2 || t1 < b2 || b1 > t2)
       return false;
    else
       return true;

    /* Or could be shortened down to
    return !(r1 < l2 || l1 > r2 || t1 < b2 || b1 > t2) */

}

quite a reduction in code wont you say ;)

like image 105
rflood89 Avatar answered Jan 26 '23 03:01

rflood89