Problems with slow movement speeds

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.
placeholder
Prole
Posts: 13
Joined: Mon Mar 15, 2021 9:00 pm

Problems with slow movement speeds

Post by placeholder »

Hi, I'm just learning, and i'm wondering if anyone can take a look at this and help?

I have some sprites in my project moving around at various speeds and it's all doing well until the sprites/objects/whatever slow down, at which time they start hitching and stop moving. I'm using low resolution and some little pixel art sprites that I made to keep it simple because I have no idea what i'm doing yet

I made an example of what i'm seeing, and it's presented below. I'm using the push library.

This code breaks when the rect.speed variable is low. When rect.speed is 50-ish or above, the rectangle moves smoothly across the screen. When rect.speed = 10, the rectangle does not move. When rect.speed = 30, the rectangle moves in a lurching fashion that I would like to avoid.

I've tried removing the line that rounds the rect.x variable, but the result is again lurching movement that I would like to avoid. I'm not even sure what problem I'm trying to solve, or why this is breaking at low speed. I'm grateful for any suggestions, thanks!

Code: Select all

push = require "push"
screenWidth = 320
screenHeight = 240
push:setupScreen(screenWidth, screenHeight, screenWidth * 2, screenHeight * 2)

function love.load()
 rect = {}
 rect.x = 20
 rect.y = 20
 rect.width = 100
 rect.height = 100
 rect.speed = 10
end

function love.update(dt)
 rect.x = rect.x + rect.speed * dt
 rect.x = math.floor(rect.x + 0.5)
end

function love.draw()
 push:start()
 love.graphics.rectangle("line", rect.x, rect.y, rect.width, rect.height)
 push:finish()
end
MrFariator
Party member
Posts: 510
Joined: Wed Oct 05, 2016 11:53 am

Re: Problems with slow movement speeds

Post by MrFariator »

The thing is that you're multiplying the rect's speed by delta time, which is quite a small value (1/60, or maybe even smaller). Then, you round the number to the nearest integer (with math.floor by adding 0.5 to the resulting position), making it so that your objects can only ever more in the increments of exactly 1 integer or more. With low enough speed values, the resulting step that your rect takes in a frame will be smaller than 0.5, and your object will effectively stop. Only if dt were to increase (eq. due to a lagspike) would the object break that 0.5 barrier and get rounded out to another value.

Perhaps let the rectangles move on a more fine grained scale than full integers (ie. don't round the position at all, or round it to tenths, hundredths or something similar), but round the positions while rendering them, either during the draw step or keeping a separate rounded value somewhere.
User avatar
darkfrei
Party member
Posts: 1172
Joined: Sat Feb 08, 2020 11:09 pm

Re: Problems with slow movement speeds

Post by darkfrei »

Code: Select all

function love.update(dt)
  dt=0.5*dt -- slow down the simulation twice
  rect.x = rect.x + rect.speed * dt
end

Code: Select all

function love.draw()
  push:start()
  love.graphics.rectangle("line", math.floor(rect.x + 0.5), rect.y, rect.width, rect.height)
  push:finish()
end
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
placeholder
Prole
Posts: 13
Joined: Mon Mar 15, 2021 9:00 pm

Re: Problems with slow movement speeds

Post by placeholder »

oh wow, so i just move the object position normally, jerks and stutters and all, but i round the draw position of the object's sprite

thank you for the epiphany, i look forward to trying that out tomorrow
placeholder
Prole
Posts: 13
Joined: Mon Mar 15, 2021 9:00 pm

Re: Problems with slow movement speeds

Post by placeholder »

ok, so i tried this and it works great with horizontal and vertical movement, but causes problems with diagonal movements? the code listed below illustrates the problem.

the EXAMPLE variable can be set to 1 or 2. 1 shows what i want to see - smooth movement. but it doesn't work at slow speeds. 2 shows the fix - rounding the draw position - but the movement is choppy and stuttery. this is also a problem in my project where diagonal movement speeds are normalized, so i didn't include that in this code.

how can i make my rectangle move smoothly like example 1 without breaking at low speed?

Code: Select all

push = require "push"
screenWidth = 160
screenHeight = 120
push:setupScreen(screenWidth, screenHeight, screenWidth * 4, screenHeight * 4)

-- please set EXAMPLE to 1 or 2
-- 1 generates smooth diagonal movement, but breaks if rect.speed is set to 25-ish or below
-- 2 works at slow speed, but generates stuttery movement at all speeds FOR SOME REASON??
EXAMPLE = 1

function love.load()
 rect = {
  x = 5,
  y = 95,
  width = 10,
  height = 10,
  draw_x = 5,
  draw_y = 95,
  speed = 40
  }
end
function love.update(dt)
  if EXAMPLE == 1 then
    --
    rect.x = rect.x + rect.speed * dt
    rect.y = rect.y - rect.speed * dt
    --
    rect.x = math.floor(rect.x + 0.5)
    rect.y = math.floor(rect.y + 0.5)
    --
    rect.draw_x = rect.x
    rect.draw_y = rect.y
    --
  elseif EXAMPLE == 2 then
    --
    rect.x = rect.x + rect.speed * dt
    rect.y = rect.y - rect.speed * dt
    --
    rect.draw_x = math.floor(rect.x + 0.5)
    rect.draw_y = math.floor(rect.y + 0.5)
    --
  else
    love.event.quit()
  end
end
function love.draw()
 push:start()
 love.graphics.rectangle("fill", rect.draw_x, rect.draw_y, rect.width, rect.height)
 push:finish()
end
User avatar
darkfrei
Party member
Posts: 1172
Joined: Sat Feb 08, 2020 11:09 pm

Re: Problems with slow movement speeds

Post by darkfrei »

You round it again

rect.x = math.floor(rect.x + 0.5)
rect.y = math.floor(rect.y + 0.5)
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
ivan
Party member
Posts: 1911
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Problems with slow movement speeds

Post by ivan »

If you overwrite rect.x and rect.y the movement will be choppy and it won work when rect.speed*dt < 0.5
If you want to use rounding, then just do it when drawing:

Code: Select all

love.graphics.rectangle("fill", math.floor(rect.draw_x + 0.5), math.floor(rect.draw_y + 0.5), rect.width, rect.height)
placeholder
Prole
Posts: 13
Joined: Mon Mar 15, 2021 9:00 pm

Re: Problems with slow movement speeds

Post by placeholder »

ivan wrote: Tue Mar 16, 2021 11:45 am If you overwrite rect.x and rect.y the movement will be choppy and it won work when rect.speed*dt < 0.5
If you want to use rounding, then just do it when drawing:

Code: Select all

love.graphics.rectangle("fill", math.floor(rect.draw_x + 0.5), math.floor(rect.draw_y + 0.5), rect.width, rect.height)
I'm not sure i understand - this is what happens in example 2 - round the draw position instead of the actual position. This is the intended fix to the problem that occurs in example 1, but it also causes the movement to be choppy.

Did i code example 2 incorrectly? How is my example 2 different from your suggestion?
placeholder
Prole
Posts: 13
Joined: Mon Mar 15, 2021 9:00 pm

Re: Problems with slow movement speeds

Post by placeholder »

darkfrei wrote: Tue Mar 16, 2021 9:39 am You round it again

rect.x = math.floor(rect.x + 0.5)
rect.y = math.floor(rect.y + 0.5)
I'm not sure i'm following - this is what i'm doing in example 1, but it breaks at low speed.

Example 2 is the intended fix. The draw position is rounded instead of the actual position, but this causes choppy movement.
Last edited by placeholder on Tue Mar 16, 2021 3:27 pm, edited 1 time in total.
User avatar
darkfrei
Party member
Posts: 1172
Joined: Sat Feb 08, 2020 11:09 pm

Re: Problems with slow movement speeds

Post by darkfrei »

placeholder wrote: Tue Mar 16, 2021 6:01 am 2 shows the fix - rounding the draw position - but the movement is choppy and stuttery. this is also a problem in my project where diagonal movement speeds are normalized, so i didn't include that in this code.

how can i make my rectangle move smoothly like example 1 without breaking at low speed?
You can round your position after the moving, when the player don't press keys anymore. So the diagonal movement will be pretty diagonal.
placeholder wrote: Tue Mar 16, 2021 3:14 pm
darkfrei wrote: Tue Mar 16, 2021 9:39 am You round it again

rect.x = math.floor(rect.x + 0.5)
rect.y = math.floor(rect.y + 0.5)
I'm not sure i'm following - this is what i'm doing in example 1, but it breaks at low speed. Example 2 is the intended fix, but causes choppy movement.
If your dt*speed < 0.5, then you have no movement at all. Just make a buffer, for example as

Bad example, but you can understand what I mean.

Code: Select all

if buffer*speed < 0.5 then 
  -- skip movement for this tick
  buffer = buffer + dt
else
  -- do your movement 1 code, but use buffer instead of dt
  buffer = 0
end
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
Post Reply

Who is online

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