[Solved] Friction and FPS troubles!

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
MercatorK
Prole
Posts: 4
Joined: Tue Apr 21, 2015 8:18 am

[Solved] Friction and FPS troubles!

Post by MercatorK »

Hello! I just started using Love2D a couple of weeks ago to dive into game programming and so far I'm loving it. However, I've run into a hiccup of sorts that just perplexes me. I've made a movement system where the player basically moves a rectangle side to side, and I've added some friction to make the movement smoother. What perplexes me is that when I give it to friends to test, they say that the friction is much more slippery than when I test it.

After putting in a framerate counter, I noticed something strange. My FPS was constantly around 999 even though I've read that Love only goes up to 60. I then tried to isolate the problem further by closing all of my other programs, including Firefox and other RAM-heavy programs. After I did that, I think I went through what my testers did and noticed that the friction was way too slippery, leading me to believe that it is a framerate-related issue that causes my friction system to not work.

My code is admittedly a mess, but everything except for the friction works fine. Here's the friction code itself:

Code: Select all

Player.vel = Player.vel - Player.friction
if Player.dir == 'r' then
	  Player.x = Player.x + Player.vel * dt
elseif Player.dir == 'l' then
	  Player.x = Player.x - Player.vel * dt
end

if love.keyboard.isDown('right') and
   love.keyboard.isDown('left')==false
   then
	if (Player.vel > 0 and Player.dir == 'l') then
	  Player.vel = Player.vel - Player.friction
	  Player.x = Player.x - Player.vel * dt
	  elseif Player.vel == 0 then
	  Player.dir = 'r'
	end
	  Player.vel = Player.vel + Player.friction
	  Player.x = Player.x + Player.vel * dt
	end
   
if love.keyboard.isDown('left') and
   love.keyboard.isDown('right')==false and
   Player.crouch == false
   then
   	if (Player.vel > 0 and Player.dir == 'r') then
	  Player.vel = Player.vel - Player.friction
	  Player.x = Player.x + Player.vel * dt
	  elseif Player.vel == 0 then
	  Player.dir = 'l'
	end
      Player.vel = Player.vel + Player.friction
	  Player.x = Player.x - Player.vel * dt
    end
When I was originally writing this, the friction was 1 and player's speed was 200. After the isolation, I noticed it was very slippery and the FPS dropped to 100 rather than 1000, so I changed the friction to 10 which solved it. I attempted to put in a frame limiter in love.update in order to take care of this problem, but this did nothing when I ran it before isolation:

Code: Select all

dt = math.min(dt, 1/60)
Any help would be very much appreciated! As of writing this, when I test run it, it works fine, but Firefox is using a lower amount of memory than usual. I think this has something to do with either delta time or some memory issues.
Last edited by MercatorK on Sun Apr 26, 2015 2:09 am, edited 1 time in total.
User avatar
micha
Inner party member
Posts: 1083
Joined: Wed Sep 26, 2012 5:13 pm

Re: Friction and FPS troubles!

Post by micha »

Hi and welcome to the forum.

You code is almost fine. You will not need a framerate delimiter. Instead should make the code work with arbitrary framerates. You only need to make a few changes:
Replace this line:

Code: Select all

Player.vel = Player.vel - Player.friction
by this line:

Code: Select all

Player.vel = Player.vel - Player.friction * dt
Additionally you need to "recalibrate" the specific value of Player.friction so that you get the same game feel as you had before.

As a rule of thumb: Whenever you change something gradually, then you need to incorporate dt somewhere.
User avatar
ivan
Party member
Posts: 1918
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Friction and FPS troubles!

Post by ivan »

Yes, micha is correct, however note that:
Player.vel = Player.vel - Player.friction * dt
This is more like 'deceleration' and is constant.
Also note that Player.vel can eventually become a negative number.
I suggest:

Code: Select all

player.vel = player.vel / (1 + player.damping*dt)
Where 'damping' is a coefficient between 0 and 1.
I attempted to put in a frame limiter in love.update in order to take care of this problem, but this did nothing when I ran it before isolation:
dt = math.min(dt, 1/60)
It is possible to use a constant time step in games (in fact some physics libraries recommend it)
however it's unnecessary most of the time unless you're doing complicated things that require numerical robustness.
Here is one way of using a 'constant' time step:

Code: Select all

accum = 0 -- accumulator
step = 0.016 -- constant time step
function update(dt)
  accum = accum + dt
  while accum >= step do
    -- process player input here
    -- update the game
    accum = accum - step
  end
end
The basic idea is to calculate several 'steps' per update if delta becomes too large.
User avatar
s-ol
Party member
Posts: 1077
Joined: Mon Sep 15, 2014 7:41 pm
Location: Cologne, Germany
Contact:

Re: Friction and FPS troubles!

Post by s-ol »

ivan wrote:Yes, micha is correct, however note that:
Player.vel = Player.vel - Player.friction * dt
This is more like 'deceleration' and is constant.
Also note that Player.vel can eventually become a negative number.
I suggest:

Code: Select all

player.vel = player.vel / (1 + player.damping*dt)
Where 'damping' is a coefficient between 0 and 1.
I attempted to put in a frame limiter in love.update in order to take care of this problem, but this did nothing when I ran it before isolation:
dt = math.min(dt, 1/60)
It is possible to use a constant time step in games (in fact some physics libraries recommend it)
however it's unnecessary most of the time unless you're doing complicated things that require numerical robustness.
Here is one way of using a 'constant' time step:

Code: Select all

accum = 0 -- accumulator
step = 0.016 -- constant time step
function update(dt)
  accum = accum + dt
  while accum >= step do
    -- process player input here
    -- update the game
    accum = accum - step
  end
end
The basic idea is to calculate several 'steps' per update if delta becomes too large.
Wouldn't it be better to change love.run?

s-ol.nu /blog  -  p.s-ol.be /st8.lua  -  g.s-ol.be /gtglg /curcur

Code: Select all

print( type(love) )
if false then
  baby:hurt(me)
end
User avatar
MercatorK
Prole
Posts: 4
Joined: Tue Apr 21, 2015 8:18 am

Re: Friction and FPS troubles!

Post by MercatorK »

Thanks everyone! I fixed the problem, runs perfectly now. It was indeed because I wasn't multiplying the actual friction by dt, so its movement depended on the framerate. I originally did divide friction by dt and use the player.damping variable, but found it to drop off too exponentially compared to subtraction. I also have a limit on player.vel, so it dropping into the negatives wasn't an issue. I noticed that I had to change the friction from 1 to 1000. Here's the fixed code for what it's worth:

Code: Select all

player.vel = player.vel - (player.friction * dt)
  if player.dir == 'r' then
  player.x = player.x + player.vel * dt
  elseif player.dir == 'l' then
  player.x = player.x - player.vel * dt
end

if love.keyboard.isDown('right') and
   love.keyboard.isDown('left')==false and
   player.crouch == false
   then
	if (player.vel > 0 and player.dir == 'l') then
	  player.vel = player.vel - (player.friction * dt)
	  player.x = player.x - player.vel * dt
	  elseif player.vel <= 0.1 then
	  player.dir = 'r'
	end
	  player.vel = player.vel + player.friction * dt
	  player.x = player.x + player.vel * dt
end
   
if love.keyboard.isDown('left') and
   love.keyboard.isDown('right')==false and
   player.crouch == false
   then
   	if (player.vel > 0 and player.dir == 'r') then
	  player.vel = player.vel - (player.friction * dt)
	  player.x = player.x + player.vel * dt
	  elseif player.vel <= 0.1 then
	  player.dir = 'l'
	end
      player.vel = player.vel + player.friction * dt
	  player.x = player.x - player.vel * dt
end
User avatar
ivan
Party member
Posts: 1918
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Friction and FPS troubles!

Post by ivan »

Code: Select all

    player.vel = player.vel / (1 + player.damping*dt)
Where 'damping' is a coefficient between 0 and 1.
Just a small correction: damping a coefficient between 0 and positive infinity.
This is the formula used in Box2D.
MercatorK wrote:I originally did divide friction by dt and use the player.damping variable, but found it to drop off too exponentially compared to subtraction.
Hey, whatever works for you. :)
But like I said, subtraction is more like deceleration and would not scale well.
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: Friction and FPS troubles!

Post by Robin »

ivan wrote:

Code: Select all

    player.vel = player.vel / (1 + player.damping*dt)
I don't think that's what you want: it's not frame-rate independent, higher frame-rates result in stronger damping.

I think you must raise something to the dt-th power to make it work, but I'm not sure what the resulting formula will be. I'd use something like:

Code: Select all

    player.vel = player.vel * player.decay_rate^dt
Where player.decay_rate (in the range [0, 1]) is the fraction of the original speed the player should have after 1 second.
Help us help you: attach a .love.
User avatar
micha
Inner party member
Posts: 1083
Joined: Wed Sep 26, 2012 5:13 pm

Re: Friction and FPS troubles!

Post by micha »

Robin wrote:I don't think that's what you want: it's not frame-rate independent, higher frame-rates result in stronger damping.
That is very true.

However, if dt varies only a little bit, then this approximation will work well (everything is approximately linear for small changes).
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: Friction and FPS troubles!

Post by Robin »

micha wrote:However, if dt varies only a little bit, then this approximation will work well (everything is approximately linear for small changes).
Except that even if dt stays the same for an entire play-through, the game would still behave differently for different computers.
Help us help you: attach a .love.
User avatar
micha
Inner party member
Posts: 1083
Joined: Wed Sep 26, 2012 5:13 pm

Re: Friction and FPS troubles!

Post by micha »

You are right. I did not think of that.
Post Reply

Who is online

Users browsing this forum: Bing [Bot], Google [Bot] and 7 guests