Bug with collision detection with Tiled(LWJGL & Slick2D)

Information:
The tiled map and player : http://prntscr.com/2c445u . I tried to make some kind of pixel-precise movement
It is weird because I can achieve stuff like this sometimes : http://prntscr.com/2c44px

I can not figure out how to prevent these bugs…(It needs to works with more maps too…)I believe that the whole issue is caused by the way I calculate tileX and tileY (player’s positions @ grid. Is there a better way?)

This thing(in pic) only happens when I try to move left or right and I am in the middle of 2 tiles. Is there any way to prevent that?

(I am not a noob with java. Its just the fact that I am now taking my first steps in game-dev.)
Here is the full code:

//packet
//imports
public class LevelOne extends BasicGameState{

public int state;
boolean esc;
Input input;

private TiledMap map;

private float x,y,vel;


public LevelOne(int state){
    this.state = state;
}

@Override
public void init(GameContainer arg0, StateBasedGame arg1)
        throws SlickException {
      esc = false;
      map = new TiledMap("res/map/map.tmx");

      x = 2 * 32;
      y = 1 * 32;
      vel = .1f;
}

@Override
public void render(GameContainer arg0, StateBasedGame arg1, Graphics g)
        throws SlickException {
        map.render(0, 0);

        g.fillRect(x, y, 32, 32);

}

@Override
public void update(GameContainer gc, StateBasedGame sbg, int delta)
        throws SlickException {
    input = gc.getInput();
    if(esc){
        Mouse.setGrabbed(false);

    }else{
        Mouse.setGrabbed(true);
    }
        if(input.isKeyPressed(Input.KEY_ESCAPE)){
            esc = true;
        }   
    if(esc){
        Mouse.setGrabbed(false);
            if(input.isKeyPressed(Input.KEY_R)){
                esc = false;
            }else if(input.isKeyPressed(Keyboard.KEY_Q)){
                System.exit(0);
            }else if(input.isKeyPressed(Keyboard.KEY_M)){
                esc = false;
                sbg.enterState(0);
                Mouse.setGrabbed(false);
            }
        }

    int objLayer = map.getLayerIndex("Objects");

    int tileX = (int)(x + 1)/ 32; 
    int tileY = (int)(y + 1)/ 32;

    System.out.println(tileX +"   "+ tileY);

    //TODO -- FIX COLLISIONS

    if(input.isKeyDown(Input.KEY_RIGHT)){
        if(map.getTileId(tileX+1, tileY, objLayer) == 0){
            x+= vel * delta;
        }
    }

    if(input.isKeyDown(Input.KEY_LEFT)){

        tileX++;

        if(map.getTileId(tileX-1, tileY, objLayer) == 0){
            x-= vel * delta;
        }

        tileX--;

    }

    if(input.isKeyDown(Input.KEY_UP)){

        tileY++;

        if(map.getTileId(tileX, tileY-1, objLayer) == 0){
            y-= vel * delta;
        }

        tileY--;

    }

    if(input.isKeyDown(Input.KEY_DOWN)){
        if(map.getTileId(tileX, tileY+1, objLayer) == 0){
            y += vel * delta;
        }
    }

        }

@Override
public int getID() {
    return state;
}
}

Thanks in advance

This doesn´t look right. There are no bounding box checks, you´re just checking if the neighbouring tiles are empty and if they are the player is allowed to move. I would suggest storing all unwalkable tiles in an array and check all tiles around you. If there are any unwalkable tiles you do a bounding box check and if there is a collision/intersection you deal with the respons.

A lot have been written about AABB (“axis aligned bounding box”) in the forum so do a search for that and I´m guessing that Slick has it´s own “rectangle intersect” function that is good to go. And there was a similar question some time ago when I wrote this answer: http://www.java-gaming.org/topics/aabb-collision-detection-fails-when-moving-to-the-left/31443/msg/292675/view.html#msg292675

Take a look at this

I think I have got it now , thanks! Anyways , Axis Aligned Bounding Box. Have seen that term. Translating to my language doesnt help…

“Axis aligned bounding box” is fancy talk for “rectangle”, basically. :slight_smile: It´s the rectangle you use to check collision/intersections against objects.

“Axis aligned” means its sides are parallel with the x and y axis, or in other words it´s not rotated. Like this: http://documentation.flatredball.com/frb/docs/images/a/a2/AxisAligned.png. “Bounding box” is, well, a rectangle. :slight_smile: Most people just call it AABB and it´s a good word to remember since it´s used a lot.

After a rethink , I do not get this one. Indeed slick has it’s own Box(Bounding) and intersects/contains methods , but , what am I supposed to check?
What I think I need to check:
Check the three nearby tiles (left/right/up/down depending at the direction the player wants to move) and then determine if he is allowed to move onto that direction by checking if
A)All 3 tiles are not blocked
B)the center tile is not blocked and the player does /does not intersect with the 2 others
C)The center tile is blocked

Is this the proper way to do this?

Second attempt:

I still face a few issues with the tiles.(http://prntscr.com/2evl5c) e.g. -> http://prntscr.com/2evl92 , http://prntscr.com/2evlg6 , http://prntscr.com/2evll1

public int[][] obj; //store each tile's id of the object layer here

private TiledMap map;

private float x,y,vel, TILE_SIZE;//x position , y position ,velocity, tile size in pixels

private Sound jump;//nevermind

public boolean cLeft,cRight,cUp,cDown;//c(anMove)Left/Right/Down etc

public LevelOne(int state){
    this.state = state;//constructor to pass the 
}

@Override
public void init(GameContainer arg0, StateBasedGame arg1)
        throws SlickException {
      TILE_SIZE = 32;//initialization
      esc = false;
      map = new TiledMap("res/map/map.tmx");
      cUp = false;
      cDown = false;
      cLeft = false;
      cRight = false;
      x = 2 * TILE_SIZE;//see the map
      y = 1 * TILE_SIZE;
      vel = .1f;
      objLayer = map.getLayerIndex("Objects");//get the layer
      jump = new Sound("res/sound/jump.wav");

      obj = new int[10][10];//initialize the 2d array to store the blocked tiles

      for(int col = 0; col < 10;col++){
          for(int row = 0;row < 10;row++){
              obj[col][row] = map.getTileId(col, row, objLayer);
          }
      }
}

@Override
public void render(GameContainer arg0, StateBasedGame arg1, Graphics g)
        throws SlickException {
        map.render(0, 0);//render only the map and a white rectangle (player)

        g.fillRect(x, y, TILE_SIZE, TILE_SIZE);

}

@Override
public void update(GameContainer gc, StateBasedGame sbg, int delta)
        throws SlickException {
    input = gc.getInput();//get input
    if(esc){//somehting about the menu , ignore it!
        Mouse.setGrabbed(false);

    }else{
        Mouse.setGrabbed(true);
    }
        if(input.isKeyPressed(Input.KEY_ESCAPE)){
            esc = true;
        }   
    if(esc){
        Mouse.setGrabbed(false);
            if(input.isKeyPressed(Input.KEY_R)){
                esc = false;
            }else if(input.isKeyPressed(Keyboard.KEY_Q)){
                System.exit(0);
            }else if(input.isKeyPressed(Keyboard.KEY_M)){
                esc = false;
                sbg.enterState(0);
                Mouse.setGrabbed(false);
            }
        }


    //calculate collisions
    AABB();



    //TODO -- FIX COLLISIONS , thats what we need to do :/

    if(input.isKeyDown(Input.KEY_RIGHT)){//arrow keys, check if player can move and decide, see AABB() method!
        if(cRight){
            x += vel * delta;
        }
    }

    if(input.isKeyDown(Input.KEY_LEFT)){
        if(cLeft){
            x -= vel * delta;
        }
    }

    if(input.isKeyDown(Input.KEY_UP)){
        if(cUp){
            y -= vel * delta;
        }
    }

    if(input.isKeyDown(Input.KEY_DOWN)){
        if(cDown){
            y += vel * delta;
        }
    }

        }

@Override
public int getID() {//get the id of the class
    return state;
}

private void AABB(){

    cLeft = false;//re-initialize
    cRight = false;
    cUp = false;
    cDown = false;

    tileX = (int) Math.round(Math.ceil(x / TILE_SIZE));//get the tile of the player
    tileY = (int) Math.round(Math.ceil(y / TILE_SIZE));

    int diffX = (int) Math.round(Math.ceil(x % TILE_SIZE));//get the remainder , sorry for the name
    int diffY = (int) Math.round(Math.ceil(y % TILE_SIZE));

    int HALF_TILE_SIZE = 32 / 2;//get half the tile size

    //Start handling collisions

    if(diffX == HALF_TILE_SIZE){//if the player is actually on a number that can be divided by 32 without remainder , do a simple up/down check
        if(obj[tileX][tileY - 1] == 0){
            cUp = true;
        }   
        if(obj[tileX][tileY + 1] == 0){
            cDown = true;
        }
    }else{
        if(diffX > HALF_TILE_SIZE){//if it is not , check the other nearby squares.Here because diffX > HALF_TILE_SIZE , I get the one near these tiles. its obj[numberoftilex][numberoftiley] to get the tile's id. it returns 0 if it is empty.
            if(obj[tileX][tileY - 1] == 0 && obj[tileX + 1][tileY - 1] == 0){
                cUp = true;
            }
            if(obj[tileX][tileY + 1] == 0 && obj[tileX + 1][tileY + 1] == 0){
                cDown = true;
            }
        }else if(diffX < HALF_TILE_SIZE){
            if(obj[tileX][tileY - 1] == 0 && obj[tileX - 1][tileY - 1] == 0){
                cUp = true;
            }
            if(obj[tileX][tileY + 1] == 0 && obj[tileX - 1][tileY + 1] == 0){
                cDown = true;
            }
        }
    }
    //same things done with X are done with Y
    if(diffY == HALF_TILE_SIZE){
        if(obj[tileX - 1][tileY] == 0){
            cLeft = true;
        }

        if(obj[tileX + 1][tileY] == 0){
            cRight = true;
        }
    }else{
        if(diffY > HALF_TILE_SIZE){
            if(obj[tileX - 1][tileY] == 0 && obj[tileX - 1][tileY - 1] == 0){
                cLeft = true;
            }
            if(obj[tileX + 1][tileY] == 0 && obj[tileX + 1][tileY - 1] == 0){
                cRight = true;
            }
        }else if(diffY < HALF_TILE_SIZE){
            if(obj[tileX - 1][tileY] == 0 && obj[tileX - 1][tileY + 1] == 0){
                cLeft = true;
            }
            if(obj[tileX + 1][tileY] == 0 && obj[tileX + 1][tileY + 1] == 0){
                cRight = true;
            }
        }


    }

}