Page 1 of 1

Managing dt dependant player position

Posted: Mon Sep 01, 2014 7:27 pm
by fedexist
Good evening, everyone!

Only yesterday I've encountered an annoying problem caused by the delta time update of the player position in my test map, let me explain.

As a premise, I say that the player is moving on an orthogonal tiled map with many layers. The data structure of a layer is substantially a matrix, filled with numbers in each row. I want my player to move only on the zero correspondent tiles in the first layer of the map (just to add more infos, the map is built with Tiled and i'll provide a sample at the end).
Basically, this is the function for my player movement

Code: Select all

function Player.movement(dt)

--there's other stuff here
--delta(x,y) is the normalized vector I use to get the direction my player needs to go (obviously based off the input I receive)

		Player.velocity = Player.velocity:len() * delta + Player.acceleration * dt

		if Player.velocity:len() > Player.max_velocity then
			Player.velocity = Player.velocity:normalized() * Player.max_velocity
		end		 
		
		if Player.TestMap(math.sign(delta.x), math.sign(delta.y), dt)  then
			
			Player.position = Player.position + Player.velocity * dt
			
		end

end
while the TestMap function needs to check if the player can move (that is, if the position is allowed to update) basing on the nearby tiles, and it's like this:

Code: Select all

function Player.TestMap(x, y)

nearby_tile_walkable = current_location.data[math.ceil(actual_position.y/tilewidth)+y][math.ceil(actual_position.x/tileheight)+x] ==0
is_at_border = (x==1 and right_limit) or (x==-1 and left_limit) or (y==1 and lower_limit) or (y==-1 and upper_limit)

	if not nearby_tile_walkable and is_at_border then
		return false
	end
	
	return true
end

whereas the various limits are just like

Code: Select all

right_limit = actual_position.x == last_pixel_of_current_tile
Now, I realized the type of conditions I use in testmap are correct, but still this function can't seem to work at all. The real problem, which I figured out at least, is that since position of the player is dependant from the dt, and I can't have control of it, the limit conditions of which above can't be absolutely right at one pixel precision. As a matter of fact, If I change right_limit to this

Code: Select all

right_limit = actual_position.x <= math.ceil(actual_position.x/tilewidth)*tilewidth and actual_position.x >= (math.ceil(actual_position.x/tilewidth)*tilewidth)-10
that is, now, the player can't walk on a 10 pixel wide stripe, the problem is, almost gone, but still I have some bugs (e.g. diagonal movements or movements caused by weird sequence of input from the user).

Now, I'd like to ask if there's any way to do what I want to do without changing the hell out of the movement system. If my explanation was lacking, please point out where I can explain myself better.

As always, thank you very much for your time in reading my post :)

PS: attached for the reference is the tiled generated map

Re: Managing dt dependant player position

Posted: Tue Sep 02, 2014 5:28 am
by ivan
A couple of things to point out.
The acceleration formula is:

Code: Select all

acceleration = change in velocity / time
=>
acceleration = (final velocity - initial velocity) / time
=>
change in velocity = acceleration * time
So updating the player velocity should look like:

Code: Select all

player velocity = player velocity + acceleration * delta
player velocity = clamp ( player velocity, max velocity )
while the TestMap function needs to check if the player can move (that is, if the position is allowed to update) basing on the nearby tiles, and it's like this:
One thing this function needs to handle (if you want to have diagonal movement) is corners like these:

Code: Select all

   ___
  |
  |  o <- player
Where the player could collide with two tiles at the same time if moving diagonally.
In short, I don't believe you can handle collisions like these just by testing 1 point versus the map.
Now, I'd like to ask if there's any way to do what I want to do without changing the hell out of the movement system. If my explanation was lacking, please point out where I can explain myself better.
If you disable diagonal movement the problem becomes significantly simpler.
Or if you move the player 1 tile at a time and just interpolate as he moves from tile to tile.

If you have the time, take a look at:
http://love2d.org/forums/viewtopic.php?f=5&t=75931

Re: Managing dt dependant player position

Posted: Wed Sep 03, 2014 8:17 am
by fedexist
Ok, I see your points, thanks for the heads up. I'll try to use a collision detection system to perfect the movement and see what I'll be able to come up with.