Collision Response in 2D sidescroller?

Started by
4 comments, last by wolfscaptain 12 years, 9 months ago
Hello. This is my first attempt at making a side-scroller tile based game (similar to "Mario"). I've been researching the answer to this online for weeks and I haven't found anything helpful. If someone could point me in the right direction it would be greatly appreciated.

So far I have loaded the level into memory, and now I'm just trying to find a way so that the player can run and jump around to explore the level. The collision detection is fine (I tested it extensively and it definitely works), but I can't figure out how to respond to the collisions so that the player doesn't go through the blocks.

This is all I'm asking for: a way to detect from which direction the player collided with the block. For instance, if the player hits the block from above or below, the function will return a 1, and if the player hits the block from the side, the function will return a 0.

I already tried one method for the collision response. I calculated how deep the overlap was with the player and the ground in both the X and Y direction. Whichever overlap was less, I assumed that the player hit the block from that direction. Yet, this method turn out being very glitchy and it doesn't really work. I became very frustrated with this method and after almost a couple of days trying to fix it, I think I'm just going to abandon that method altogether.

One more request: if anyone could help me figure out how to handle the collision response when the player collides with multiple blocks, that would be appreciated as well.
Sincerely,
-Rob
Advertisement
I am currently using the same method (I believe it's called Minimum Translation Vector), and while being a little buggy (when the intersection is equal on all axes), you will not notice it most of the time.
A way to fix it when the intersection is indeed the same, is to also take your velocity in consideration to figure in which direction you should push your character to.

To solve collisions with multiple tiles, I "hacked" and just did two collision checks one after another, but you probably want to find a better way.

If you still feel it's too buggy for you, you should take a look into real collision detection - one that takes time into consideration, and will solve things much more cleanly (and will not allow tunneling either).

Now this is not relevant to the collision detection directly, but if you use a 2D grid where every tile has the same size as all the rest, you can have amazing optimizations to both rendering and collision detection.
You can get the exact group of tiles that are visible on the screen, and only draw those. This can be done with a few mathematical operations, taking into consideration the size of each tile (on each axis in case your tiles are not square), the resolution (I myself abstracted it to "tiles per screen" which is easier to handle in my opinion), and the location your "camera" is, in the world.
Similarly, you can find the exact group of tiles your character might collide with, using the same information, and the size of your character. For example, if your character is the same size or smaller then a tile, you only need to check it against 9 tiles at the worst case.

Hope this helps a little.
I too am currently working on a game like this and have the same problem. My method for response (does not work completely) is to calculate a line equation between where it was last when it didn't collide to its current colliding position. I then positioned my player at that colliding position and moved it along that line in the reverse direction it had been previously been moving in until it did not collide.

For my collision detection, if your level is made of an array of blocks you can use the mod operator to check the nearest block to the player's 4 corners by accessing the array through x and y.
So for example this:


blkx=xpos-(xpos%10); blky=ypos-(ypos%10);
blkx/=10; blky/=10;
if (Blk[blkx][blky].tp!="") {return true;}


Where the level is made up of 10x10 blocks and xpos/ypos is the position of the corner of the player's bounding box.
If it hasn't exploded, I haven't touched it.
Are you using pixel based collision, or primitive(such as AABB) collisions??

It tends to be better in platformers to use primitive collisions, and is easier to make things smooth that way. Truthfully though, the last poster has it right. If the geometry you are colliding with is static, you can simply "re-trace" to get where you are no longer colliding. But, this may not be feasible. For example, if Mario hits his head on a block, and you use that method, while jumping to the right, you will get pushed back left again, as you collide with the block. So, you have to combine both your "Minimum Translation Vector" with the re-tracking method. If you use the vectors and distances to determine you are closer to the bottom than to the side, then you can do the re-tracing only on that vector. So instead of re-tracing the line back to the previous position, you would simply go along the up/down/y vector until you are no longer colliding, by simply lowering the y a little(assuming y-positive is the Up direction). You will want to do something similar if you determine the collision is to the side, but with the x-vector instead. And you likely want to maintain your y-speed if that is the case, so you can slide up/down the wall if you bump it in the middle of a jump. You wouldn't want to hit the side of the wall, and suddenly be pushed down, when you still have enough "uummpphh" to finish going up.

You may also want to include velocity checking as well, for example so that you could utilize jumpthrough platforms. Say, you want to jump up to a platform going through it. That platform specifically would only allow collision detection if you are coming from the top, and so you check your speed/direction/velocity to either land on the platform(similar to the above paragraph) or to simply let you slide through it. You would do the same thing the other way, if you allow moving back down when holding the down key(like in the Contra games for NES/SNES.


You just made me realize how inefficient my engine is. I use two collision checks every step, once after calculating the player's X movement and once after calculating the player's Y movement. But it works perfectly.

For example:

In the X check, if the player moved right and is now colliding with a block, it must of collided with it on its left side. So the player moves to the block's left edge.

In the Y check, if the player fell and is colliding with a block, then it must of collided on its top surface, so the player is moved accordingly.

You could try that if it doesn't reduce the framerate. Though I'm sure there's a more efficient way of doing it.

The good news of doing it axis at a time is that it will never explode when intersection is the same on both axes (causing teleportation), the bad news is that it just won't solve them correctly, imgine a scenario in your head.

Your detection code needs to only return a vector that pushes you outside of the intersection, then your game logic can use it with extra information (such as your velocity) to solve it correctly.

Collision detection and response are cleaner when not stuck together.

This is what I do, anyway.

This topic is closed to new replies.

Advertisement