Platformer collision detection

Hello,

I’m currently trying to build a platformer game and try to get the collision detection working. The code for the collision detection is the following. It is basicly the code from the LibGDX test game superkalio:


private void checkCollisionsPlayervsMap(float deltaTime) {
		// perform collision detection & response, on each axis, separately
		// if the player is moving right, check the tiles to the right of it's
		// right bounding box edge, otherwise check the ones to the left

		Rectangle playerRect = rectPool.obtain();
		playerRect.set(player.position.x, player.position.y, Player.width, Player.height);
		int startX, startY, endX, endY;
		if (player.velocity.x > 0) {
			startX = endX = (int) (player.position.x + Player.width + player.velocity.x);
		} else {
			startX = endX = (int) (player.position.x + player.velocity.x);
		}
		startY = (int) (player.position.y);
		endY = (int) (player.position.y + Player.height);
		getTiles(startX, startY, endX, endY, tiles);
		playerRect.x += player.velocity.x;
		for (Rectangle tile : tiles) {
			if (playerRect.overlaps(tile)) {
				player.velocity.x = 0;
				break;
			}
		}
		playerRect.x = player.position.x;

		// if the player is moving upwards, check the tiles to the top of it's
		// top bounding box edge, otherwise check the ones to the bottom

		if (player.velocity.y > 0) {
			startY = endY = (int) (player.position.y + Player.height + player.velocity.y);
		} else {
			startY = endY = (int) (player.position.y + player.velocity.y);
		}
		startX = (int) (player.position.x);
		endX = (int) (player.position.x + Player.width + player.velocity.x);
		getTiles(startX, startY, endX, endY, tiles);
		playerRect.y += player.velocity.y;

		for (Rectangle tile : tiles) {
			if (playerRect.overlaps(tile)) {
				if (player.velocity.y > 0) {
					player.position.y = (tile.y - Player.height);
				} else {
					player.position.y = (tile.y + tile.height);
					player.grounded = true;
				}
				player.velocity.y = 0;
				break;
			}
		}
		rectPool.free(playerRect);

		// unscale the velocity by the inverse delta time and set
		// the latest position

		player.position.add(player.velocity);
		player.velocity.scl(1 / deltaTime);
		// Apply damping to the velocity on the x-axis so the player dosen't
		// walk infinitely once a key was pressed

		player.velocity.x *= Player.DAMPING;
	}

private void getTiles(int startX, int startY, int endX, int endY, Array<Rectangle> tiles) {
		TiledMapTileLayer layer = (TiledMapTileLayer) map.getLayers().get("ground");

		rectPool.freeAll(tiles);
		tiles.clear();
		for (int y = startY; y <= endY; y++) {
			for (int x = startX; x <= endX; x++) {
				Cell cell = layer.getCell(x, y);
				if (cell != null) {
					Rectangle rect = rectPool.obtain();
					rect.set(x, y, 1f, 1f);
					tiles.add(rect);
				}
			}
		}
	}

The problem is, sometimes when I’m jumping towards an edge, the player gets stuck on it. See the following gif:

Can someone help me to get the code working right? Or do you need more information?

check collision + player speed!

I’m not quite sure what you mean. I’m adding the current velocity to x/y position and check, if the rectangles overlap. Can you tell me what exactly you mean?

this is how i do it and it works perfect!

		double moveAmount = speed * deltaTime; // Players Speed + The DeltaTime
		
		if(left){
			
			if(!Collision.PlayerBlock(
					//LEFT DOWN
					new Point( (int) (xpos + Map.xOffset - moveAmount),
							   (int) (ypos + Map.yOffset + height)),
					//LEFT UP
					new Point( (int) (xpos + Map.xOffset - moveAmount), 
							   (int) (ypos + Map.yOffset)))){
					//MOVE MAP
					Map.xOffset -= moveAmount;
			}
		}

Best advise I can give you is stop copy and pasting code if you are learning. Other than that, break the code down into chunks and try to figure out what specific statement is causing the problem. Use conditional break points and such.

fwiw. I didn’t spent much time figuring out how your code works exactly(thus maybe i shouldnt post this, but I’m doing it anyway^__^), but it looks to me your vertical (+horizontal) collision check is returning positive when falling down and your y (+x) velocity is set to 0.

I had something similar in a game of mine.

what you could do for the vertical (y dimension) check is not check for collision over the full width of the player, but maybe (width - 1) or -2 or something (same for horizontal check).

That did it for me. But in that game i created 4 player rectangles (bot.left.right,up) for the player, and that might not be the best way to do it.

You could also try and set the player back 1px or the actual amount of movement the player gets updated with every frame (instead of only setting the velocity to 0) whenever there is collision with a tile. That way you prevent the edges of your rectangle to both trigger horizontal and vertical collision detection.

One thing I can’t really figure out by your code is why the rectangle is only stopping half way in while at the start of the gif it is placed perfectly on top of the tile…

Thank you for your answers. Maybe I will try your suggestions later, but for now I came to another solution. I changed the part:


for (Rectangle tile : tiles) {
         if (playerRect.overlaps(tile)) {
            player.velocity.x = 0;
            break;
         }
}

into:


for (Rectangle tile : tiles) {
      if (playerRect.overlaps(tile)) {
		if (player.velocity.x > 0) {
                      player.position.x = (tile.x - Player.width);
                } else {
                       player.position.x = (tile.x + tile.width);
		}
		player.velocity.x = 0;
      break;
	}
}

I’ve had this problem once as well. This might have to do with checking collision after moving the player. Try doing it before moving, one axis at a time. Before moving you should check if you can actually add n pixels to the axis. The reply above should get the job done if you cant get it done this way.