Please help me with collisions

I am fairly new to Java and after studying most of the basics I started making a 2D state change game with the help of online tutorials, the game is a simple car racing game with a overhead view kind of like pokemon, with simple left right forward backward and diagonal movements. I have got everything I need and have written most of the code but am stuck with collisions. I understand the basic concept of setting up collisions (or at least I think I do) and the way I have seen it done in the past is you set a rectangle around the car and a rectangle around the object on the map and set an if statement saying if intersects change direction to - or something similar to that, but am having trouble putting this into my code and am hoping some of the more experienced users could help me out, the code for my game is shown below, I have not posted things like the menu class and the main class just because it would overcrowd things, but if needed please tell me.

The collision I want to set is a rectangle at coordinates:

Top left: -115, -100
Top right: -360, -100
Bottom right: -360, -280
Bottom left: -115, -280

and the rectangle of my car which is a 40x40 image.

I would just like this one collision to be explained to me or shown to me in my code and I will be able to set all the others on my own with the knowledge I gain from this one.


package javagame;
 
import org.newdawn.slick.*;
import org.newdawn.slick.state.*;
 
public class Play extends BasicGameState{
         
    Animation bucky, movingUp, movingDown, movingLeft, movingRight, movingBL, movingBR, movingFL, movingFR;
    Image worldMap;
    boolean quit = false;//gives user to quit the game
    int[] duration = {200, 200};//how long frame stays up for
    float buckyPositionX = 0;
    float buckyPositionY = 0;
    float shiftX = buckyPositionX + 320;//keeps user in the middle of the screem
    float shiftY = buckyPositionY + 160;//the numbers are half of the screen size
         
    public Play(int state){
    }   
    public void init(GameContainer gc, StateBasedGame sbg) throws SlickException{
          worldMap = new Image("res/world.png");
          Image[] walkUp = {new Image("res/b.png"), new Image("res/b.png")}; //these are the images to be used in the "walkUp" animation
          Image[] walkDown = {new Image("res/f.png"), new Image("res/f.png")};
          Image[] walkLeft = {new Image("res/l.png"), new Image("res/l.png")};
          Image[] walkRight = {new Image("res/r.png"), new Image("res/r.png")};
          Image[] walkBL = {new Image("res/bl.png"), new Image("res/bl.png")};
          Image[] walkBR = {new Image("res/br.png"), new Image("res/br.png")};
          Image[] walkFL = {new Image("res/fl.png"), new Image("res/fl.png")};
          Image[] walkFR = {new Image("res/fr.png"), new Image("res/fr.png")};
     
    movingUp = new Animation(walkUp, duration, false);
    movingDown = new Animation(walkDown, duration, false);  
    movingLeft = new Animation(walkLeft, duration, false);  
    movingRight = new Animation(walkRight, duration, false);
    movingBL = new Animation(walkBL, duration, false);
    movingBR = new Animation(walkBR, duration, false);
    movingFL = new Animation(walkFL, duration, false);
    movingFR = new Animation(walkFR, duration, false);
    bucky = movingDown;//facing screen initially on startup
    }
     
     
    public void render(GameContainer gc, StateBasedGame sbg, Graphics g) throws SlickException{
    worldMap.draw(buckyPositionX, buckyPositionY);//position 0,0
    bucky.draw(shiftX, shiftY);//makes him appear at center of map
    g.drawString("Suraj's X: "+buckyPositionX+"\nSuraj's Y: "+buckyPositionY,400,20);//tells us the position
     
    if(quit==true){
        g.drawString("Resume(R)", 250, 100);
        g.drawString("Main(M)", 250, 150);
        g.drawString("Quit Game(Q)", 250, 200);
        if(quit==false){
            g.clear();//wipe off everything from screen
        }
    }
    }
     
    public void update(GameContainer gc, StateBasedGame sbg, int delta)throws SlickException{
    Input input = gc.getInput();
    //up
    if(input.isKeyDown(Input.KEY_UP)){
        bucky = movingUp;//changes the image to his back
        buckyPositionY += 10;;//increase the Y coordinates of bucky (move him up)
        if(buckyPositionY>162){//if I reach the top 
            buckyPositionY -= 10;//stops any further movement in that direction
        }
    }
     
    //down
    if(input.isKeyDown(Input.KEY_DOWN)){
        bucky = movingDown;
        buckyPositionY -= 10;
        if(buckyPositionY<-600){
            buckyPositionY += 10;//basically change the direction if + make -
    }}
    //left
    if(input.isKeyDown(Input.KEY_LEFT)){
        bucky = movingLeft;
        buckyPositionX += 10;
        if(buckyPositionX>324){
            buckyPositionX -= 10;//delta * .1f
    }}
    //right
    if(input.isKeyDown(Input.KEY_RIGHT)){
        bucky = movingRight;
        buckyPositionX -= 10;
        if(buckyPositionX<-840){
            buckyPositionX += 10;
    }}
     
     
     
     
    //2 key combos start here
    if(input.isKeyDown(Input.KEY_RIGHT) && input.isKeyDown(Input.KEY_UP)){
        bucky = movingBR;
        buckyPositionX -= delta * .1f;
        if(buckyPositionX<-840){
            buckyPositionX += delta * .1f;
            if(buckyPositionY>162){
                buckyPositionY -= delta * .1f;
            }}}
    if(input.isKeyDown(Input.KEY_LEFT) && input.isKeyDown(Input.KEY_UP)){
        bucky = movingBL;
        buckyPositionX -= delta * .1f;
        if(buckyPositionX>324){
            buckyPositionX -= delta * .1f;
            if(buckyPositionY>162){
                buckyPositionY -= delta * .1f;
            }}}
    if(input.isKeyDown(Input.KEY_RIGHT) && input.isKeyDown(Input.KEY_DOWN)){
        bucky = movingFR;
        buckyPositionX -= delta * .1f;
        if(buckyPositionY<-600){
            buckyPositionY += delta * .1f;
            if(buckyPositionX<-840){
                buckyPositionX += delta * .1f;
            }}}
    if(input.isKeyDown(Input.KEY_LEFT) && input.isKeyDown(Input.KEY_DOWN)){
        bucky = movingFL;
        buckyPositionX -= delta * .1f;
        if(buckyPositionY<-600){
            buckyPositionY += delta * .1f;
            if(buckyPositionX>324){
                buckyPositionX -= delta * .1f;
            }}}
     
     //escape
    if(input.isKeyDown(Input.KEY_ESCAPE)){
        quit=true;
    }
    //when the menu is up
    if(quit==true){//is the menu on the screen
        if(input.isKeyDown(Input.KEY_R)){
            quit = false;//resumes the game, makes menu dissapear
        }
        if(input.isKeyDown(Input.KEY_M)){
            sbg.enterState(0);//takes you to the main menu
        }
        if(input.isKeyDown(Input.KEY_Q)){
            System.exit(0);//quits the game
        }
    }
     
}
     
    public int getID(){
        return 1;
    }
}

Thank you for your help in advance.

There is a super fast rectangle-vs-rectangle collision algorithm here:
http://www.gamedev.net/page/resources/_/technical/game-programming/collision-detection-r735

Pokemon is not a true top down game, just saying. Viewpoint is angled 45 degrees back.

Thank you for the replies.

P0jahn then link you had posted seems very interesting and helpful but as I am a noob with Java I am having a hard time understanding exactly what I have to do, I would like to use the first code on the website (which seems to be the simplest):


// Object-to-object bounding-box collision detector:
short int Sprite_Collide(sprite_ptr object1, sprite_ptr object2) {
   
    int left1, left2;
    int right1, right2;
    int top1, top2;
    int bottom1, bottom2;
 
    left1 = object1->x;
    left2 = object2->x;
    right1 = object1->x + object1->width;
    right2 = object2->x + object2->width;
    top1 = object1->y;
    top2 = object2->y;
    bottom1 = object1->y + object1->height;
    bottom2 = object2->y + object2->height;
 
    if (bottom1 < top2) return(0);
    if (top1 > bottom2) return(0);
 
    if (right1 < left2) return(0);
    if (left1 > right2) return(0);
 
    return(1);
 
};

Am I correct in thinking object one and object two are the two rectangles that I need to make around my player and the house on the map? If so, how exactly do I make these rectangles and where do I place the code above and the rectangle code in my code(under the render method, update method or something else)?

Also, would this code work if I wanted to set up more than one collision, for example my map contains many houses, would this code work for that or would a Recatngle getBound() type method with a if (intersects) way work better? (I dont really know either of them two very well but types of code have seen a bit of both done before)

I am sorry for asking all these questions which may seem very easy to you, I am new with Java and might take a while to understand simple things. Thank you.

I guess… simply, this is the exact same method written in java, which I use, and it’s working:


public static boolean rectVsRect(Rect r1, Rect r2) {
	// Sperating axis theorem simplified for AABBes.
	if ((r1.x >= (r2.x + r2.w)) || ((r1.x + r1.w) <= r2.x)) {
		return false;
	}
	if ((r1.y >= (r2.y + r2.h)) || ((r1.y + r1.h) <= r2.y)) {
		return false;
	}
	return true;
}

This is the fastest AABB vs AABB collision detection algorithm known to me, so… yeah :slight_smile: It’s just the same as the C++ version above, but implemented in java without this redunant int allocations :slight_smile:

If you have a tile map you can do it even quicker. (when colliding with the tile map)
Just cast the coords of each corner to ints, and check those points to see if they equal the tile coords.

This got me thinking if it was possible to do the same, but to scale/translate the coords of one rectangle and then do the same method as above.

Anyone done this before?

Yes I do do what you suggested at first :wink:
this would be done like that:


public static int clamp(int val, int min, int max) {
    return Math.max(Math.min(val, max), min);
}

public static boolean collidesWithMap(Map map, Rect rect) {
    int beginx = ((int) rect.x) / map.getTileWidth();
    int beginy = ((int) rect.y) / map.getTileHeight();
    int endx = ((int) rect.x + rect.w) / map.getTileWidth() + 1;
    int endy = ((int) rect.y + rect.h) / map.getTileHeight() + 1;
    // Clamp the values to the map's dimensions:
    beginx = clamp(beginx, 0, map.getWidth());
    beginy = clamp(beginy, 0, map.getHeight());
    endx = clamp(endx, 0, map.getWidth());
    endy = clamp(endy, 0, map.getHeight());
    // Iterate over the found "possible" tile positions:
    for (int y = beginy; y < endy; y++) {
        for (int x = beginx; x < endx; x++) {
            if (map.getTile(x, y) != null) { // or something like: map.isTileAt(x, y), which should return a boolean then
                return true;
            }
        }
    }
}

Thank you for the help, Matheus23, the code you ave shown in your post:


public static boolean rectVsRect(Rect r1, Rect r2) {
   // Sperating axis theorem simplified for AABBes.
   if ((r1.x >= (r2.x + r2.w)) || ((r1.x + r1.w) <= r2.x)) {
      return false;
   }
   if ((r1.y >= (r2.y + r2.h)) || ((r1.y + r1.h) <= r2.y)) {
      return false;
   }
   return true;
}

How do I put this code into my code and how do I set up my r1 and r2 to be my player(the car) and the collision (the house)?

Basically, I have this ‘Rect’ class:


public class Rect {

	public float x;
	public float y;
	public float w;
	public float h;

	public Rect() {
		set(0, 0, 1, 1);
	}

	public Rect(float w, float h) {
		set(0, 0, w, h);
	}

	public Rect(float x, float y, float w, float h) {
		set(x, y, w, h);
	}

	public Rect set(float x, float y, float w, float h) {
		this.x = x;
		this.y = y;
		this.w = w;
		this.h = h;

		return this;
	}

	public float right() {
		return x + w;
	}

	public float bottom() {
		return y + h;
	}

}

Then you’d need to create a Rect for your car and a Rect for your house. You have to position the rects to match the positions and sizes of the car / house, and then you’d check collisions with the method I gave you :slight_smile:

Thank you for helping me Matheus23, I am sorry for asking noob questions but could you please tell me how I would continue after making the Rect class please, I think I have a basic Idea of what I need to do but keep messing up, so to start off, is this how I would make the rectangles:


public Rectangle getBounds() {
     return new r1(x, y, width, height);//I would set this as r1 for the car and r2 for the house?
 }

So I would make 2 of the above code, 1 for the house and one for the car, but would I have to make a object of the Rect class to be able to do this? Also, under what section of code would I place this, would it be under my Render method or my Update method or something else?

The I would have to place your if statement into my code, but again,where would this be placed(in the render, update, other)?

This code does nothing… better fix it! :persecutioncomplex:

Haha! I made a quicker collision detection method than you. 8) ;D (not referring to my previous post)

My entities have their coords in the centre, and their size value is half the real size.


//Like this
leftSide = pos.x - size.x;
rightSide = pos.x + size.x;
//And so on for y coords

So collision detection is similar to circles (but with 2 checks (for each axis))


if(Math.abs(pos.x-other.pos.x) < size.x + other.size.x)
{
//Do same for Y axis
}

Only 2 checks.

Beat that!

You don’t need pastebin for short code. :point:

Can anyone please tell me how to make a rectangle around my player and my house, am I supposed to use the code bellow?


public Rectangle getBounds() {
     return new r1(x, y, width, height);//not too sure if this is supposed to be r1
 }

If so, where do I place this code in my code?

nah, since “Rect” is a class, it’s supposed to be [icode]new Rect(…)[/icode]…

Then how does java know the difference between 2 different rectangles, I mean if I say that code twice (1 for the house 1 for the car) how will java know what r1 is and what r2 is?

I gave you this method: [icode]public static boolean rectVsRect(Rect r1, Rect r2) { … }[/icode]. You can invoke this method using [icode]boolean houseAndCarColliding = rectVsRect(houseRect, carRect);[/icode].

Then how do you get houseRect and carRect? Simply create them as a class member:


public Rect houseRect = new Rect([insert house-x-position], [insert house-y-position], [insert house-width], [insert house-height]);
public Rect carRect = new Rect([insert car-x-position], [insert car-y-position], [insert car-width], [insert car-height]);

But the questions you’ve asked seem to be a bit more about java itself… probably you should read some more tutorials or source code in java.

:& Fixing… (forgets things when he doesn’t test code… :persecutioncomplex: )