2D tile map collision detection

Started by
6 comments, last by Khatharr 11 years, 4 months ago

I've got a problem with my tilemap based collision detection. The problem is getting stuck on walls and I was wondering what the method is to tackle this issue.

For example moving left/right works ok and also checking for solid tiles above and below. However diagonal movement causes the issue where the player sprite sticks to the wall.

Currently if a check is made on a point around the sprite for example -1 pixel and this tile is found to be solid then the player x position is set to be to the right on the solid tile (player.position.x = (tile.X / 16)+ player.width) - so in effect the player just stops moving left.

Should you first check for and correct X positioning before moving onto checking and correcting Y positioning? Currently I am checking X/Y then correcting X/Y.

Thanks.

Advertisement

the way i would do it is to just do a bounding box collision check, then if there was a collision i would correct on the axis with the lowest penetration value. the penetration value is how far one bounding box has penetrated another . so you get the penetration value of both the x axis and the y axis. and correct for the smallest penetration value. you can get the penetration value by taking the distance from the center of the bounding box to the edge of the bounding box "width/2 or height /2". for both bounding boxes, and then subtract it from the distance from the center of box 1 to the center of box 2:



int Xpenetration=( ( Boundingbox1.width/2 + Boundingbox2.width/2 ) - (Boundingbox2.centerX-Boundingbox1.centerX) );

int Ypenetration=( ( Boundingbox1.height/2 + Boundingbox2.height/2 ) - (Boundingbox2.centerY-Boundingbox1.centerY) );

then you compare the absolute value of both the Xpenetration and the Ypenetration, and just correct for the smallest value:


if( abs(Xpenetration) > abs(Ypenetration) )
{
   // correct on the y axis using Ypenetration value.
}
else 
{
   // correct on the x axis using Xpenetration value.
} 

So are you suggesting that once I have detected a collision based upon a tilemap check, I then perform a bounding box collision using the tilemap tile coords and the player bounding box coords?

Can you show the collision handling code?

I'm thinking I know the problem (someone else recently posted the same problem) but it helps to be sure.

In short, allowing diagonal motion means you need to segregate collision reactions per-axis. It's easier to express in code, or to point out the reason that the code is failing.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

Its a bit unclear how you are handling the generic collision testing. Could you elaborate a little bit more?

for example, since it is tile-based, can we assume you have a multi-tier grid to partition the space?

the general algorithm I've seen over and over is something like this:

assume:

- each character has a bounding-box that is either calculated at run time or pre-calculated on a per-frame basis. In other words, you have the rectangular "space" your guy occupies

- each character also has its x,y coordinates stored somewhere

1) for each character, do a bounding-box vs space partition test. For example, if you are using multi-leveled grids then you would "query" the grid for the possible tiles that collide with the character's bounding box. If you get no results, then you know that there are no collisions

2) for each possible tile you collide with in (1), re-check the character's bounding box against the tile, removing all the tiles that you DON'T collide with

3) now for each remaining tile, you can offset the character's x and y location using a similar algorithm to what xinifinite33 mentioned to "stop" the character from going thru the tile.

There are other algorithms i'm sure, and your information provided is a bit vague so I apologize if this is more info / different info than you wanted

I would suggest using the velocity to create an up vector of sorts, you could use this to "bounce" the sprite away from the collision point by a small but safe distance. This would prevent the blocking when walking against a wall, the basic idea is a few simple steps.

Use the X & Y Velocities to create an up vector (+1/-1 X & Y Values indicating direction sprite is traveling).

Invert the up vector based on collision surface facing (or orientation if you will)

Use this new inverted up vector to apply a minimal position shift (back to last non blocking tile in that direction maybe?)

The important part is that you are sure to only affect the axis corresponding to the facing of the collision surface. (If you make collision traveling along the X axis you should only affect a change on the X axis). I would assume that right now you are doing something that completely stops or shifts both X and Y axis independent of the collision axis. Shoot me an email (found on my profile) if you need some more information.

Dan Mayor

Professional Programmer & Hobbyist Game Developer

Seeking team for indie development opportunities, see my classifieds post

Thanks for all the replies they are very helpfull!

I woke up a but early this morning (6:00 am now) and had another go and it turned out the points I was checking for collisions were a bit close or overlapping. So when my code was checking for left right collisions the points that checked for downward collisions were also triggered meaning that hitting a wall in the X direction also triggered code for landing on a platform so the player character just stuck to the wall.

If it's a Spiderman game then you're ready to ship.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

This topic is closed to new replies.

Advertisement