Jump to content

2D Collision Detection

prolemur

I have a player that can currently move wherever it is in the world he wants, even though there are walls! He must be restricted and only allowed to walk on the floor, no wall walking for him... yet.

 

So I have an x and y variable which is the position of the player which is the shape of a circle with a radius of 10. I have a map around him currently made from 80x80 squares that are stored in an array of integers. Every value of 0 is floor and the 1's are walls. He should not be able to cross into a part of the map that is a wall, but should be able to stand on the areas of the map that equal 0.

 

Some code that is relevant to my question, and also would it be better to check if the wall was hit and move the player back to to the edge of the wall or check if the next movement would make the player walk inside the wall and prevent it by setting the players position adjacent to the wall, same as the other option?

var x : real := 200var y : real := 200var speed : real := 5var mapwidth : int := 8var mapheight : int := 8var map : array 0 .. mapwidth - 1, 0 .. mapheight - 1 of intvar wallsize : int := 80% character movementif control (KEY_UP_ARROW) then    x -= x - (cos (angle) * speed + x)    y -= y - (sin (angle) * speed + y)elsif control (KEY_DOWN_ARROW) then    x += x - (cos (angle) * speed + x)    y += y - (sin (angle) * speed + y)end if% drawing wallsfor y : 0 .. mapheight - 1    for x : 0 .. mapwidth - 1        if map (x, y) = 0 then            Draw.FillBox (x * wallsize, y * wallsize, (x + 1) * wallsize, (y + 1) * wallsize, 12)        elsif map (x, y) = 1 then            Draw.FillBox (x * wallsize, y * wallsize, (x + 1) * wallsize, (y + 1) * wallsize, 7)        end if    end forend for

Thanks :)

 

Link to comment
Share on other sites

Link to post
Share on other sites

A simple way to check this (since you are using a tile map) is by calculating your new coordinates, then checking if it hit something, and if it didn't set the position to the new position.
This would be the simplest solution I can come up with on top of my head, let me know if you have trouble.

Link to comment
Share on other sites

Link to post
Share on other sites

A simple way to check this (since you are using a tile map) is by calculating your new coordinates, then checking if it hit something, and if it didn't set the position to the new position.

This would be the simplest solution I can come up with on top of my head, let me know if you have trouble.

The player doesn't move tile to tile though. I'm not sure how I would implement this also I want the x and y to continue to be separate so if the player is hitting something in front of them, in the y-direction, then they can still slide off of it to the right or left depending on their angle. If any more code is needed to figure this out I can show you it.

 

Edit: I actually got it done, I had to divide things by the size of the wall and make that an integer first.

if map (floor ((x + cos (angle) * speed) / wall), floor (y / wall)) = 0 then    x += cos (angle) * speedend ifif map (floor (x / wall), floor ((y + sin (angle) * speed) / wall)) = 0 then    y += sin (angle) * speedend if

I also realized that I could turn this into a function and make the backwards version just change the speed to a negative or something :D

Link to comment
Share on other sites

Link to post
Share on other sites

Never mind I jumped the gun, this is a very bad "solution".

 

I need the real deal that isn't just check if moving in the current direction would collide with a wall, and move if it doesn't.

Link to comment
Share on other sites

Link to post
Share on other sites

I am not the best at collision resolving, but I might be able to help. One thing you could try is move to create a vector from the tile to the player, snap that to be perpendicular with the side it's going through, and then taking a perpendicular vector from that. Then you have a vector you can move along without hitting the wall. 
You could also go for the following trick: you do a AABB intersection test, and if you intersect, you check on which axis is the minimal intersection, and push the player out of the tile on that axis.

 

I always found collision resolving to be quite tricky and a process that you just need to tune until it works.
Let me know if you need any more help.

Link to comment
Share on other sites

Link to post
Share on other sites

So there are a few things regarding collision to be mindful of.

 

The first is the width of the object, and the second is where the origin of the image is.

 

e.g. is the x,y coordinate of the player actually the bottom left, center left, top left, bottom right, bottom center...etc.  I will assume for this purpose the bottom left is the (x, y) coordinate of the player (you could adjust accordingly)

 

So now this becomes a simple collision detection of rectangles.  The important thing here is there are 4 points on a rectangle, and you currently are only checking a single point.

 

So here is my pseudo code for it

map(floor(x/width), floor(y/width)) == 1 //Wall collision at bottom left side//means you are going leftmap(floor((x+playerwidth), floor(y/width)) == 1 //Wall collision bottom right sidemap(floor(x/width), floor((y+playerwidth)/width)) == 1 //Wall collision at top left sidemap(floor((x+playerwidth), floor((y+playerwidth)/width)) == 1 //Wall collision at top rightside

So really you need to check all 4 sides for the collision

0b10111010 10101101 11110000 00001101

Link to comment
Share on other sites

Link to post
Share on other sites

-snip-

Ah that makes sense. Thank you very much! Ok so this worked to find when the player hits a wall, but in the code I changed a bit from yours since my players origin is its center being a circle and some other variable names.

if map (floor (((x + size * 2) / wall) mod wall), floor ((y / wall) mod wall)) = 0 and map (floor (((x - size * 2) / wall) mod wall), floor ((y / wall) mod wall)) = 0 then    x += cos (angle) * speedend ifif map (floor ((x / wall) mod wall), floor (((y + size * 2) / wall)) mod wall) = 0 and map (floor ((x / wall) mod wall), floor (((y - size * 2) / wall)) mod wall) = 0 then    y += sin (angle) * speedend if

What happens is the player will be stopped at a wall along the x axis of the wall and will not be able to move vertically. This is especially a problem when he goes into a corner and can't move at all since he's touching a wall along the x and y direction.

Link to comment
Share on other sites

Link to post
Share on other sites

Ah that makes sense. Thank you very much! Ok so this worked to find when the player hits a wall, but in the code I changed a bit from yours since my players origin is its center being a circle and some other variable names.

if map (floor (((x + size * 2) / wall) mod wall), floor ((y / wall) mod wall)) = 0 and map (floor (((x - size * 2) / wall) mod wall), floor ((y / wall) mod wall)) = 0 then    x += cos (angle) * speedend ifif map (floor ((x / wall) mod wall), floor (((y + size * 2) / wall)) mod wall) = 0 and map (floor ((x / wall) mod wall), floor (((y - size * 2) / wall)) mod wall) = 0 then    y += sin (angle) * speedend if

What happens is the player will be stopped at a wall along the x axis of the wall and will not be able to move vertically. This is especially a problem when he goes into a corner and can't move at all since he's touching a wall along the x and y direction.

 

Well in the case of getting trapped in walls, this actually starts getting into how you decide to implement your physics.

 

You could make it so when you detect a collision when traveling right you only block moving right (and not left).  With similar concepts for up and down.  This actually means you could travel through walls if you are spawned inside of them (ie you don't get trapped).

 

Another option would be to block the movement before you collide with a wall...ie. instead of using x, and y make a tempx and tempy which has the position if you were to move.

tmpX = x + cos (angle) * speedtmpY = y + sin (angle) * speedif map (floor (((tmpX + size * 2) / wall) mod wall), floor ((tmpY / wall) mod wall)) = 0 and map (floor (((tmpX - size * 2) / wall) mod wall), floor ((tmpY / wall) mod wall)) = 0 then    x = tmpXend ifif map (floor ((tmpX / wall) mod wall), floor (((tmpY + size * 2) / wall)) mod wall) = 0 and map (floor ((tmpX / wall) mod wall), floor (((tmpY - size * 2) / wall)) mod wall) = 0 then    y = tmpYend if

Something similar to that...

 

Either way it will depend on how you decide you want your physics.

0b10111010 10101101 11110000 00001101

Link to comment
Share on other sites

Link to post
Share on other sites

Well in the case of getting trapped in walls, this actually starts getting into how you decide to implement your physics.

 

You could make it so when you detect a collision when traveling right you only block moving right (and not left).  With similar concepts for up and down.  This actually means you could travel through walls if you are spawned inside of them (ie you don't get trapped).

 

Another option would be to block the movement before you collide with a wall...ie. instead of using x, and y make a tempx and tempy which has the position if you were to move.

tmpX = x + cos (angle) * speedtmpY = y + sin (angle) * speedif map (floor (((tmpX + size * 2) / wall) mod wall), floor ((tmpY / wall) mod wall)) = 0 and map (floor (((tmpX - size * 2) / wall) mod wall), floor ((tmpY / wall) mod wall)) = 0 then    x = tmpXend ifif map (floor ((tmpX / wall) mod wall), floor (((tmpY + size * 2) / wall)) mod wall) = 0 and map (floor ((tmpX / wall) mod wall), floor (((tmpY - size * 2) / wall)) mod wall) = 0 then    y = tmpYend if

Something similar to that...

 

Either way it will depend on how you decide you want your physics.

Ok thanks for explaining that. I don't have time to implement it yet, but if it works or I can't figure it out I will be back to this thread :P

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×