0
votes

I am making a simple tile-based game . When it comes to collision detection, I tend to fail. It is the 3rd time trying to get a pixel-precise movement correctly. 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

This is the class I made. //package //imports public class LevelOne extends BasicGameState{ //state is this class' id , objLayer is the id of the layer to check the collisions , tileX,Y = position on tiles public int state,objLayer,tileX,tileY; boolean esc; Input input;

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;
            }
        }


    }

}

}//did it help?

1
calling Math.round() on Math.ceil() seems redundant - vandale
Redundant "wrapping". Anyway , did you find anything that seems incorrect? I am still searching :/ - user3029101
Could you please comment your code, your logic/variables meaning is not entirely clear - vandale
@vandale I did, you may now take a look. - user3029101

1 Answers

0
votes

Am making the following assumptions:

  1. the tile starts at 0, and is TILE_SIZE wide so it spans 0 to TILE_SIZE - 1
  2. the origin of the grid (tile 0,0) is in the upper left corner of the grid
  3. there is a border of non-empty tiles around the edges, so the player tile can never go off the edge
  4. the player tiles x and y coordinates of the player tile are the position for the pixel at (TILE_SIZE/2 ,TILE_SIZE/2 ) relative to its top left corner

Assumed mapping of variables to tiles

I believe adding the following code block at the end of AABB() should fix it:

    if(diffX>HALF_TILE_SIZE){
        cRight=true;
    }else if(diffX<HALF_TILE_SIZE){
        cLeft=true;
    }
    if(diffY>HALF_TILE_SIZE){
        cDown=true;
    }else if(diffY<HALF_TILE_SIZE){
        cUp=true;
    }

You forgot to take into account that if the player is to the right, then they can go left. In the picture above the player should be able to move up, left and right; however you code will not take into account that there is free space in the current square to move.