8 directional collision detection in a 2d sprite game

This topic is 3476 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

Here is what I have done so far: I've got a function that takes a Vector2 that holds the player's motion (based on which direction they are trying to move via the controller or keyboard). The function also returns the Vector2 at the end, and the vector is added to the player's position so he will move in the particular direction. Inside the function, I want to handle collision checks and if the player shouldn't go a certain direction (because of a collision), then the Vector2 will be modified before it is returned.
if (tileMap.Collision.GetCellIndex(up.X, up.Y) == 1)

if (EngineHelper.GetRectangleFromPoint(up).Intersects(collisionRectangle))

motion.Y = 0;

if (tileMap.Collision.GetCellIndex(upRight.X, upRight.Y) == 1)

if (EngineHelper.GetRectangleFromPoint(upRight).Intersects(collisionRectangle))

motion.X = 0;

if (tileMap.Collision.GetCellIndex(right.X, right.Y) == 1)

if (EngineHelper.GetRectangleFromPoint(right).Intersects(collisionRectangle))

motion.X = 0;

if (tileMap.Collision.GetCellIndex(downRight.X, downRight.Y) == 1)

if (EngineHelper.GetRectangleFromPoint(downRight).Intersects(collisionRectangle))

motion.X = 0;

if (tileMap.Collision.GetCellIndex(down.X, down.Y) == 1)

if (EngineHelper.GetRectangleFromPoint(down).Intersects(collisionRectangle))

motion.Y = 0;

if (tileMap.Collision.GetCellIndex(downLeft.X, downLeft.Y) == 1)

if (EngineHelper.GetRectangleFromPoint(downLeft).Intersects(collisionRectangle))

motion.X = 0;

if (tileMap.Collision.GetCellIndex(left.X, left.Y) == 1)

if (EngineHelper.GetRectangleFromPoint(left).Intersects(collisionRectangle))

motion.X = 0;

if (tileMap.Collision.GetCellIndex(upLeft.X, upLeft.Y) == 1)

if (EngineHelper.GetRectangleFromPoint(upLeft).Intersects(collisionRectangle))

motion.X = 0;

The player can kind of wiggle into tiles that they shouldn't though. Going from the top down into the tiles works good for this. It's like they can get into them from the side angles. I tried adjusting both X & Y on the corner tiles and it still happens. I've also tried it without using Intersects method. I tried using Rectangle.Top vs Bottom, etc. I've basically tried this as many different ways as I can think of and I'm stumped. (BTW, the == 1 is what a collision tile would return) What I would ideally like to have is if the player is trying to move in the up right direction and they are already up against tiles on the right that are collision tiles, the player's motion.X will be 0 but his y won't be adjusted. So he can kind of hug the wall all the way up. It currently does this for the left and right walls but I want it to be able to do the same thing for the up and down. However this is secondary to a collision detection system that actually works properly.

Share on other sites
I'm not clear what you're doing exactly, so here's two thoughts:

If you're doing movement by cell, as in you're either on a space or you aren't, then you can just check to see if something is collidable or not, and don't even need to do the collision check. If its collidable, you alter the movement. The hugging issue can be helped by checking the surrounding tiles, such as when moving "downleft", if there's a collision, check the tile directly below you and directly to the left. If one of those is open, then move there. You'll have to decide for yourself which direction gets priority (down or left).

If you're a character moving freely around a tiled world, and can be "between" tiles, then the issue is more complex than you are making it (this probably isnt the case since you're checking the cells as "up", "upright", etc). For example, checking to see if you hit the "upright" rect doesn't tell you if you hit it from its bottom or its left. You won't know which movement to constrain (X or Y). You can do a check for WHEN you hit the tile by altering the P = V*t formula, checking, for example, at what time your "top.y" == the other's "bottom.y". From there, you probably want to change the amount of movement, not to 0, but to a value that will move you as close as possible to the rect (you'll find out how much to move from the formula).

Share on other sites
Quote:
 Original post by TimptationIf you're a character moving freely around a tiled world, and can be "between" tiles, then the issue is more complex than you are making it (this probably isnt the case since you're checking the cells as "up", "upright", etc). For example, checking to see if you hit the "upright" rect doesn't tell you if you hit it from its bottom or its left. You won't know which movement to constrain (X or Y). You can do a check for WHEN you hit the tile by altering the P = V*t formula, checking, for example, at what time your "top.y" == the other's "bottom.y". From there, you probably want to change the amount of movement, not to 0, but to a value that will move you as close as possible to the rect (you'll find out how much to move from the formula).

Yeah the 2nd one is what I'm trying to do. I have a 2d array that holds texture indexes and I use that to draw the game world. I have another 2d array that has a 1 if a particular tile should be blocked. I use the center of the player's sprite to determine which cell the player is technically on. So some of the player's sprite can be on top of the surrounding cells. So I create a rectangle for the player's sprite himself rather than the cell he is standing in. I also get the cell that the player would technically be standing in and then I get the 8 surrounding cells (up upright, etc). I create a rectangle from each of those cells and then I check each one to see if the player's sprite rectangle would collide with them.

What is the P = V*t formula? I'm not familiar with it

Share on other sites
P = V*t is "position equals velocity times time". I should've been more specific actually and wrote P' = P + (V*t) or "the new position equals the old position plus the velocity times time". With that, you can see for example what time you hit the left side of the collidable rect on your right by plugging in the x value of its left side for the new position (P') (where your character should stop moving basically), and the x value of your character's current right side for the current position (P). Velocity (V) is your movement of course. Then compare that time (t) to the other side you might have hit, and see which happend first. Then you can alter the movement correctly. Another problem I ran into is which tile to test against first. You might do something similar to find out which tile you need to "hit" first and adjust appropriately. I ended up making a list of "tiles I collided with" and sorting them by time, and then testing what I hit first, and moving out of it, then testing any second tile (on a different axis, since there's no point in moving out of MORE tiles below me, we should already be out of them, so what's the first tile on the left or right?) again to see if I still hit that as well (for example moving down and right might put you in something below AND to your right, so you cant just move out of the bottom tile) I know this sounds kinda complex, and it sort of is. My function to handle this was horrible looking (so long...lol). Sorry if this is really confusing, its just a lot to write and think about heh.

[Edited by - Timptation on June 4, 2009 12:49:25 AM]

1. 1
2. 2
3. 3
Rutin
23
4. 4
5. 5
khawk
14

• 9
• 11
• 11
• 23
• 10
• Forum Statistics

• Total Topics
633653
• Total Posts
3013153
×