Collision detection response issue

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
User avatar
Gorus
Prole
Posts: 9
Joined: Sat Jan 11, 2014 8:33 pm

Collision detection response issue

Post by Gorus »

Hello fellow coders.
I have stumbled upon a problem while writing a code for my top-down tile-map game.
Note that the player's movement isn't restricted to tiles, it's free movement.

Firstly, to get any idea of what I'm trying to do I'll post the way I use the basic default

Code: Select all

for i,lev in ipairs(level_draw) do
	if CheckCollision(player.x + (player.xvel * dt)*2, player.y + (player.yvel * dt)*2, player.height, player.width, lev.x, lev.y, level.tile_h, level.tile_w) then
		if lev.tile_id == '1' then
			player.xvel = 0
			player.yvel = 0
		end
	end
end
And here's the movement code

Code: Select all

if love.keyboard.isDown('d') and player.xvel < player.speed then
	player.xvel = player.xvel + player.speed * dt
end
	
if love.keyboard.isDown('a') and player.xvel > -player.speed then
	player.xvel = player.xvel - player.speed * dt
end
	
if love.keyboard.isDown('w') and player.yvel > -player.speed then
	player.yvel = player.yvel - player.speed * dt
end
	
if love.keyboard.isDown('s') and player.yvel > -player.speed then
	player.yvel = player.yvel + player.speed * dt
end
And the friction code (pretty much copy-paste from a tutorial on youtube)

Code: Select all

player.x = player.x + player.xvel * dt
player.y = player.y + player.yvel * dt
player.xvel = player.xvel * (1 - math.min(dt*player.friction, 1))
player.yvel = player.yvel * (1 - math.min(dt*player.friction, 1))


The collision works perfectly fine, however, the issue I found is that this makes the controls bad, for example, if I move down causing a collision with a tile below me, and then, while still holding the move down key I press left, I would expect to be able to move left while not being allowed to move down. Note that I know that when the collision is detected, it sets both velocities to 0 therefor disabling the behavior I want from even happening, but that is the entire problem here, I have spent 2 days now stumped on how to make it happen.

Any input would be appreciated.

P.S. to the board admins, sorry I submitted this issue twice, I apparently missed the part where it says posts have to be approved and though it was just somehow eaten.
Last edited by Gorus on Sun Jan 12, 2014 2:40 pm, edited 2 times in total.
User avatar
micha
Inner party member
Posts: 1083
Joined: Wed Sep 26, 2012 5:13 pm

Re: Collision detection response issue

Post by micha »

If the colliding tiles are all on the grid, then it is enough to decouple the two coordinate axes:

First move the player only in x direction and check for collision, if so then correct the x-velocity.
Then do the same for the y direction.
User avatar
Gorus
Prole
Posts: 9
Joined: Sat Jan 11, 2014 8:33 pm

Re: Collision detection response issue

Post by Gorus »

You mean like run a check on when the friction is calculated for each direction?
The problem with this kind of friction function is that even when the player is still, the xvel and yvel variables have a value, that's constantly changing from 0 to 3 or something like that, because of the delta time used in the function.
By the way, the movement is not restricted to one direction, it's fully analog.

I will, however, give this a shot and edit this post with the results.

EDIT: well I tried attaching the check for each direction of movement (inside the keyboard.isDown functions) and it now does what I intended it to do, however, I'm worried if so many checks don't cause a huge amount of calculations?

EDIT2: attached a check after the velocity calculations if they are higher than the oscillating dt number and it seems to work perfectly now. I kinda feel like the movement is stuttering a bit, doesn't really eat up a lot of cpu or memory, but it seems to be stuttering anyway. Also noticed that x axis collision while moving on y axis as well now causes x axis to decelerate to 80% of the speed and then jump back up, while the same thing on y axis doesn't do that and the movement is fluid. Any ideas?
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Collision detection response issue

Post by ivan »

And the friction code (pretty much copy-paste from a tutorial on youtube)

Code: Select all

player.x = player.x + player.xvel * dt
player.y = player.y + player.yvel * dt
player.xvel = player.xvel * (1 - math.min(dt*player.friction, 1))
player.yvel = player.yvel * (1 - math.min(dt*player.friction, 1))
This is not friction but "damping". "Friction" generally means loss in velocity when the edges of two shapes are touching.
Also I believe that the way you apply damping might be incorrect. You want to apply it to both the X and Y axis at the same:

Code: Select all

-- clamps number between two values
function clamp(n, low, high)
  return math.min(math.max(n, low), high)
end

    -- damping
    local damp = clamp(1 - DAMPING*dt, 0, 1)
    player.xvel = player.xvel*damp
    player.yvel = player.yvel*damp
Where DAMPING is the damping value for the moving object.
Gorus wrote:

Code: Select all

if love.keyboard.isDown('d') and player.xvel < player.speed then
	player.xvel = player.xvel + player.speed * dt
end
	
if love.keyboard.isDown('a') and player.xvel > -player.speed then
	player.xvel = player.xvel - player.speed * dt
end
	
if love.keyboard.isDown('w') and player.yvel > -player.speed then
	player.yvel = player.yvel - player.speed * dt
end
	
if love.keyboard.isDown('s') and player.yvel > -player.speed then
	player.yvel = player.yvel + player.speed * dt
end
The collision works perfectly fine, however, the issue I found is that this makes the controls bad, for example, if I move down causing a collision with a tile below me, and then, while still holding the move down key I press left, I would expect to be able to move left while not being allowed to move down
There are a few problems with your code. First, your velocity will be greater when you move diagonally.
If you want to be restrict movement to 1 direction at a time you have to write something like:

Code: Select all

if isDown('w') then

elseif isDown('a') then

elseif isDown('s') then

elseif isDown('d') then

end
Notice the elseif instead of "if".
Note that I know that when the collision is detected, it sets both velocities to 0 therefor disabling the behavior I want from even happening, but that is the entire problem here, I have spent 2 days now stumped on how to make it happen.
This is a non-trivial issue in a sense that there is no simple, general solution.
You can't just set the velocity to 0 for several reasons.
Your code checks for a collision in the NEXT frame and sets the player's velocity to 0. This will leave a gap between the player and the shape he is supposed to collide with.
Usually, you want to:
1. move the player based on his velocity
2. check for overlap (intersection) between the player and all other shapes
3. move the player so that he is not overlapping any shapes
4. adjust the player's velocity accordingly
The most complicated part is (4) because you have to figure out how you want your player to respond to collisions. Do you want him to "slide" along edges of walls or should he stop (aka friction)? Do you want your player to bounce off walls or stick to them (aka bounce or restitution).
I wrote a short tutorial on collisions: http://love2d.org/forums/viewtopic.php?f=5&t=75931 that you might find helpful.

Also take a look at some of the other (simpler) collisions libs like kikito's bump.lua or my humble fizzx for inspiration.
User avatar
Gorus
Prole
Posts: 9
Joined: Sat Jan 11, 2014 8:33 pm

Re: Collision detection response issue

Post by Gorus »

Thanks for the insight, I'll have a look at that.
I have however fixed all the issues by placing some checks above the velocity calculations, but I feel like there's way too much work the CPU has to do so maybe the solutions you provided will help solve that.
I'll make a new post if something goes terribly wrong, but for now I think I got all the info I need.
Thanks

EDIT: I uploaded the love file so that you can check out the result of what I have so far. Press M to generate a map, wasd to move, currently I have 2 maps (very stupid maps, just for testing) that have a 50% chance of appearing when you press M again, try the movement and tell me how it feels.
Attachments
zelda ripoff.love
(8.68 KiB) Downloaded 172 times
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Collision detection response issue

Post by ivan »

Gorus wrote:Thanks for the insight, I'll have a look at that.
I have however fixed all the issues by placing some checks above the velocity calculations, but I feel like there's way too much work the CPU has to do so maybe the solutions you provided will help solve that.
Runs fine on my machine. If you plan to have many projectiles in there you might have some slowdown because the number of collision checks increases exponentially without some sort of partitioning.
Gorus wrote:I'll make a new post if something goes terribly wrong, but for now I think I got all the info I need.
Cool. One thing I noticed however: the player slows down as he approaches walls. Since your collision checks are frame based and dt varies each frame, the larger the dt the greater the gap between the player and the wall. This is not a big deal but if you have fast moving objects it might become more noticeable.
User avatar
Gorus
Prole
Posts: 9
Joined: Sat Jan 11, 2014 8:33 pm

Re: Collision detection response issue

Post by Gorus »

ivan wrote: Cool. One thing I noticed however: the player slows down as he approaches walls. Since your collision checks are frame based and dt varies each frame, the larger the dt the greater the gap between the player and the wall. This is not a big deal but if you have fast moving objects it might become more noticeable.
Would replacing dt in those calculations with a set value impact the game in a bad way?
Also, dt can be drastically different on each machine right? I guess I'll have to find a way to do it without dt, as if someone has a slower pc and the dt is bigger, the movement could be different.
User avatar
micha
Inner party member
Posts: 1083
Joined: Wed Sep 26, 2012 5:13 pm

Re: Collision detection response issue

Post by micha »

If the objects stop with a short distance before the wall, then this is probably because of a programming error:

When you detect a collision, then you should not fully reverse the last step by putting the object back to the original position. Instead you should move the object to the closest position, where no collision occurs.

Here an example: The object is at position x=1. The wall at position x=2. Then in one timestep you move the object to position x=2.5. Which makes a collision. Your code puts the object back to x=1, which makes a gap again. Instead it should be moved to x=2.
User avatar
Gorus
Prole
Posts: 9
Joined: Sat Jan 11, 2014 8:33 pm

Re: Collision detection response issue

Post by Gorus »

micha wrote:If the objects stop with a short distance before the wall, then this is probably because of a programming error:

When you detect a collision, then you should not fully reverse the last step by putting the object back to the original position. Instead you should move the object to the closest position, where no collision occurs.

Here an example: The object is at position x=1. The wall at position x=2. Then in one timestep you move the object to position x=2.5. Which makes a collision. Your code puts the object back to x=1, which makes a gap again. Instead it should be moved to x=2.
I don't change the position of the object, I make the velocity = 0 when object is near a wall. I do see your point though, and I think I have some ideas on how to fix all of that. Probably will have to rewrite the whole collision handle. Thanks for the insight.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Bing [Bot] and 5 guests