Page 1 of 1

(SOLVED) Newbie problem with dt

Posted: Sun Feb 14, 2016 5:19 pm
by molul
I'm trying to code a basic tiledbased platformer following this guide and Sonic's Physics Guide (http://info.sonicretro.org/SPG:Running).

My current problem is that I don't seem to be able to handle "dt" properly. If I set or unset vsync in this simple test, the player moves really differently and I don't get why. I use dt in "CHero:updateSpeedX" when adding acceleration or deceleration constant to speed. I thought I should use it in "CHero:updatePosition" too (changing it to self.x = self.x + (self.spX * dt)) but the result is still very different with vsync on and off.

Would someone please tell me what I'm doing wrong? I'd love finally understanding one of my common mistakes. I bet it must be a very basic thing.

Code: Select all

CHero = class:new()

function CHero:init (x, y)
	self.x 				= x or 300
	self.y 				= y or 210
	self.width 			= gTileSize
	self.height 		= (2 * gTileSize)
	self.edgeX 			= x
	self.edgeY 			= y
	
	self.spX 			= 0
	self.maxSpX 		= 1000
	self.acc 			= 5
	self.dec 			= 10
	self.friction 		= 5
end

function CHero:update(dt)
	self:updateSpeedX(dt)
	self:updatePosition(dt)
end

function CHero:updateSpeedX(dt)
	if (gKeyPressed.left) then 
		if (self.spX > 0) then 
			self.spX = self.spX - (self.dec * dt)
		elseif (self.spX > -self.maxSpX) then 
			self.spX = self.spX - (self.acc * dt)
		end
	elseif (gKeyPressed.right) then 
		if (self.spX < 0) then 
			self.spX = self.spX + (self.dec * dt )
		elseif (self.spX < self.maxSpX) then 
			self.spX = self.spX + (self.acc * dt)
		end
	else 
		self.spX = self.spX - math.min(math.abs(self.spX), (self.friction * dt)) * math.sign (self.spX)
	end
end

-- UPDATE POSITION
function CHero:updatePosition(dt)
	self.x = self.x + self.spX
end


--DRAW
function CHero:draw()
	love.graphics.setColor(self.color)
	love.graphics.rectangle('fill', self.x, self.y, self.width, -self.height)
	love.graphics.setColor(255,255,255)
end
Thanks a lot in advance.

Re: Newbie problem with dt

Posted: Sun Feb 14, 2016 5:24 pm
by bobbyjones
What is the fps with vsync off? If it's 1000 then I would assume that dt wouldn't do much. Dt still affects things. It just makes it less different. I bet if you removed dt completely you would see it move extremely fast at both 1000 and 60 fps. (Also it could be something obvious that I don't see)

Edit 1: when adding your speed to your position you need to use dt. It's in the linear kinetics equation.

Code: Select all

 d = di + vi*t + 1/2a*t^2 
 --or 
 d = di + V*t -- this is what you are doing. t is dt. Or should be doing anyways.

Re: Newbie problem with dt

Posted: Sun Feb 14, 2016 5:35 pm
by molul
Thanks bobbyjones. Fps are more or less 660 with vsync off. Does it make sense that the code is behaving really different from 60 to 660 fps then?
bobbyjones wrote: Edit 1: when adding your speed to your position you need to use dt. It's in the linear kinetics equation.

Code: Select all

 d = di + vi*t + 1/2a*t^2 
 --or 
 d = di + V*t -- this is what you are doing. t is dt. Or should be doing anyways.
I'll give it a try again. The problem is, when updating position, the collision detection makes something like

hero.speed = min(hero.speed, closerTileDistance)

as seen in the first link in the OP. I'll try to fix that.


EDIT: adding "dt" to the line where "x" is updated with "speedX" does nothing. With Vsync On it accelerates instantly, while with Vsync Off it slowly builds speed.

I hate it when I can't get to work such a basic thing XD

Re: Newbie problem with dt

Posted: Sun Feb 14, 2016 6:56 pm
by Tesselode
Post all your current code so far. It mostly seems right, although...should math.abs(self.spX) (under the else line) be math.abs(self.spX * dt)?

Re: Newbie problem with dt

Posted: Sun Feb 14, 2016 8:51 pm
by zorg
To my eyes, the following stood out where dt could have been missing:

Code: Select all

-- UPDATE POSITION
function CHero:updatePosition(dt)
   self.x = self.x + self.spX -- from here
end
Edit: nevermind, just saw that you tried this already, and it didn't work; yes, please post your code then instead :3

Re: Newbie problem with dt

Posted: Mon Feb 15, 2016 7:25 am
by molul
Checking all my current code might be a bit tedious. This evening I'll reduce it as much as I can and I'll post it. Thanks for the help so far! :)

Re: Newbie problem with dt

Posted: Mon Feb 15, 2016 7:57 am
by molul
Here's a a simplified version of this test. The problem is the same and there's not as much code to read :)

EDIT: keys are left and right arrows, and esc to close.

Re: Newbie problem with dt

Posted: Mon Feb 15, 2016 8:23 am
by Kingdaro
Try this for your update method instead. I notice it could be simplified a bit, and doing that might be a good path towards a solution.

Code: Select all

function CHero:updateSpeedX(dt)
   local targetSpeed =
      gKeyPressed.left and -self.maxSpX or
      gKeyPressed.right and self.maxSpX or
      0

   self.spX = self.spX + (targetSpeed - self.spX) * math.max(dt * self.acc, 1)
end
It uses a linear interpolation formula to interpolate the player's speed to its max speed, in the direction depending on which key is down. math.max() is used so the speed is guaranteed not to exceed the maximum or minimum speed. In other words, the line says "slowly change this value towards this other value over time".

It doesn't factor in deceleration or friction, but you could probably figure that yourself.

Re: Newbie problem with dt

Posted: Mon Feb 15, 2016 9:33 am
by molul
Thanks Kingdaro. This works the same with vsync on or off if I set "self.x = self.x + (self.spX * dt)" in CHero:updatePosition(dt).

However, if possible, I'd like to know what was wrong in my updateSpeed function. I mean, some theory like "you shouldn't use dt here if you already used it there" or "you can't use dt twice in the same function", or something like that. I'm sure I'll find myself in similar situations in the future and I'd like to be able to figure out myself what's wrong :)


EDIT: ok, I think I figured it out :D My main problem was that I wasn't using "self.x = self.x + (self.spX * dt)" in CHero:updatePosition(dt). I removed the " * dt" in my full code because, after updating speed and before updating position, I was also checking the closest tile distance, with the final line "hero.speed = min (hero.speed, closestTileDistance)". I have to rework that part.

I tried fixing that problem by adding the line "hero.speed = hero.speed * dt" at the end of the updateSpeed function. That's very wrong, as speed will always be really slow.

Finally, another problem is that I was using very low values for the hero's top speed, acceleration, deceleration and friction.

Thanks for the quick replies everyone. I think I can manage to fix this now ^_^