Stuttering when moving display objects across screen?

Can’t seem to figure out what’s causing this?

I’ve created an Endless Runner that runs at 60fps. The playable character never actually moves. Rather, I have an enterframe function that spawns objects for him to jump over and translates them across the screen at a fixed speed, which is stored in a variable called scrollSpeed (I currently have it set to -3, meaning the objects move from right to left). This creates the illusion of a scrolling background. Once the objects finish their course and move off the screen they delete themselves. That’s all there is to this project, nothing more, nothing less. I don’t see the need to post code because it’s literally only about a dozen lines just as I’ve described.

Anyways, in both the simulator and when I build the project for my Android, I notice something weird. The objects that scroll across the screen kind of jerk and stutter. It’s a very slight, subtle jerk to the direction opposite of which it’s travelling, before it returns to it’s normal course, but once you notice it you can’t un-notice it. I tried using deltaTime to solve this issue but it actually made the jerking motion noticeably WORSE. So…what gives? I’ve googled this and I’m not the only person who’s had this issue (link1, link2) but unfortunately I’m yet to see a confirmed solution.

EDIT: Yet another link outlining this issue.

Any solutions?

  1. If you want help with a code based issue, you should always post your code (or simple code demonstrating the issue).  

  2. I think you’re making some assumptions that are not always right:

a.  You say you move three (3) pixels every frame?  That won’t give smooth motion. Frames don’t occur in equally spaced periods.  i.e. If you’re expecting there to be 16.66 ms between each frame exactly you’ll be disappointed.  

b. Why 60FPS?  More FPS doesn’t always mean smoother.  In fact, if you have any heavy lifting (long calculations) to do later in your game and you do it each frame, you’ll bog down on slower devices.  I rarely use 30 FPS.

  1. Here is one example that takes variable frame time into account:

    local cx = display.contentCenterX local cy = display.contentCenterY local cw = display.contentWidth local startX = cw + 100 local endX = 0 - 100 local ch = display.contentHeight local last local bs = 20 – Yes, this is the block size local speed = 100 – 100 pixels per second local getTimer = system.getTimer local lastMove = getTimer() local pieces local onEnterFrame = function( ) local rightmostX = -math.huge local curTime = getTimer() local dt = curTime - lastMove lastMove = curTime local dx = speed * dt / 1000 if( pieces ) then for k,v in pairs( pieces ) do v.x = v.x - dx if( v.x < endX ) then pieces[v] = nil display.remove(v) elseif(v.x>rightmostX) then rightmostX = v.x end end end local tmp if( not pieces ) then pieces = {} tmp = display.newRect( startX + bs, cy, bs, bs) elseif( rightmostX < (startX - bs) ) then tmp = display.newRect( rightmostX + bs, cy, bs, bs) end if( tmp ) then pieces[tmp] = tmp tmp:setStrokeColor(0,1,0) tmp.strokeWidth = 1 end end Runtime:addEventListener( “enterFrame”, onEnterFrame )

  2.  This method uses transition, but I don’t like it much as it can develop gaps due to floating-point errors during placement and synchronization disconnects between transitions and enterFrame events:

    local cx = display.contentCenterX local cy = display.contentCenterY local cw = display.contentWidth local startX = cw + 100 local endX = 0 - 100 local ch = display.contentHeight local last local bs = 20 – Yes, this is the block size local speed = 100 – 100 pixels per second local getTimer = system.getTimer local lastMove = getTimer() local pieces local onEnterFrame = function( ) local rightmostX = -math.huge if( pieces ) then for k,v in pairs( pieces ) do if( v.x < endX ) then pieces[v] = nil display.remove(v) elseif(v.x>rightmostX) then rightmostX = v.x end end end local tmp if( not pieces ) then pieces = {} tmp = display.newRect( startX + bs, cy, bs, bs) elseif( rightmostX < (startX - bs) ) then tmp = display.newRect( rightmostX + bs, cy, bs, bs) end if( tmp ) then tmp.onComplete = function( self ) pieces[self] = nil display.remove(self) end pieces[tmp] = tmp tmp:setStrokeColor(0,1,0) tmp.strokeWidth = 1 local dx = tmp.x - endX local time = 1000 * dx/speed transition.to( tmp, { x = endX, time = time, onComplete = self } ) end end Runtime:addEventListener( “enterFrame”, onEnterFrame )

  3. Here is a physics based solution.  I like this because it better synchronizes with enterFrame(), but I don’t like it because it can make things ‘complicated’ later.  It is also semi-costly. since it uses the physics engine to do the calculations.

    local physics = require “physics” physics.start() local cx = display.contentCenterX local cy = display.contentCenterY local cw = display.contentWidth local startX = cw + 100 local endX = 0 - 100 local ch = display.contentHeight local last local bs = 20 – Yes, this is the block size local speed = 100 – 100 pixels per second local getTimer = system.getTimer local lastMove = getTimer() local pieces local onEnterFrame = function( ) local rightmostX = -math.huge if( pieces ) then for k,v in pairs( pieces ) do if( v.x < endX ) then pieces[v] = nil display.remove(v) elseif(v.x>rightmostX) then rightmostX = v.x end end end local tmp if( not pieces ) then pieces = {} tmp = display.newRect( startX + bs, cy, bs, bs) elseif( rightmostX < (startX - bs) ) then tmp = display.newRect( rightmostX + bs, cy, bs, bs) end if( tmp ) then tmp.onComplete = function( self ) pieces[self] = nil display.remove(self) end pieces[tmp] = tmp tmp:setStrokeColor(0,1,0) tmp.strokeWidth = 1 physics.addBody( tmp, “kinematic” ) tmp.isSensor = true tmp:setLinearVelocity( -speed, 0 ) end end Runtime:addEventListener( “enterFrame”, onEnterFrame )

These all look fairly similar to solutions I’ve tried and I have even tried switching to 30 FPS. Even then, there’s still a slight “jitter” of the objects moving across the screen. I even copy and pasted your initial solution, and the jittering was still occurring, I could tell because the thickness of the stroke lines kept slightly changing. If you can give me a couple of minutes I’ll throw together a quick video capture to help you see what’s going on and edit it into this post.

Unfortunately my screen capture software caused the Corona simulator to slow down considerably and couldn’t really capture what I was talking about, but I found a video from elsewhere that does:

https://www.dropbox.com/s/bn17r80047mh2sv/corona_scroll_test.mp4

If you put it in full screen and look closely at the circle you’ll notice it’s jerking back and forth and not moving along smoothly. This looks far worse when you’re using multiple shapes with distinct edges like Boxes, up against a contrasting background. I wish I could show you how it looks for me but as of right now I don’t have the means.

You can’t rely on the lines looking right.  Try these examples with a complex image.  The lines getting thicker and narrower is a scaling artifact.

Upon further investigation your initial solution does in fact work. I implemented it into my project and in both the simulator and on my phone the game now runs very smoothly.

I guess the key difference here is that my implementation of dt had dt divided by (1000/display.fps.) Yours only divides by 1000 and ditches the fps part from what I can see? And as a result instead of using a scrollSpeed of 3 it had to be adjusted to a much higher number. Perhaps if you could provide comments or a quick explanation regarding the difference here? That’s the biggest difference I’ve spotted, but it definitely works.

A thousand thank yous. This issue was driving me up the wall lol.  :slight_smile:

You’re welcome.  I think the difference you mentioned boils down to:

  1. 1000/display.fps - is  a constant

  2. my dt is variable based on elapsed time since the last frame.

Please note that display.fps never changes.  It is either 30 or 60 based on what was in config.lua.

One more small note.  Recall that I said above, you should always include your code when asking code questions.

I asked this because it allows folks who answer (like myself) to see exactly what assumptions you’ve made.  I wasn’t picking on you.

It is natural to think that ‘my code is fine’ and there is a problem elsewhere, but when you tell me what your code is doing versus showing me your code, this bias covers up the problem.  i.e. If you’d posted the code with ‘1000/display.fps’ I’d have seen the problem immediately.  Then I could have saved time and pointed out the logic error instead of coding three examples.

So, best of luck in your coding endeavors, but remember to post code next time please. 

Hey roaming, as it turns out after extensive testing my game is actually still experiencing major stuttering and performance issues. I see this website doesn’t have a PM feature. Is there somewhere where I can privately contact you and share my project and the code, and have you take a look at it on your end? Maybe do some testing? Just want to make sure this isn’t a problem specific to the devices I’m using at this point.

I may not be able to help you. I’m pretty busy and have to be cautious about doing free work (besides the occasional forums answer).  

That said, I’ll take a peek and if something pops out I’ll let you know either way.

My e-mail is:  rgemail2.png

Just sent the e-mail. Thanks again!

  1. If you want help with a code based issue, you should always post your code (or simple code demonstrating the issue).  

  2. I think you’re making some assumptions that are not always right:

a.  You say you move three (3) pixels every frame?  That won’t give smooth motion. Frames don’t occur in equally spaced periods.  i.e. If you’re expecting there to be 16.66 ms between each frame exactly you’ll be disappointed.  

b. Why 60FPS?  More FPS doesn’t always mean smoother.  In fact, if you have any heavy lifting (long calculations) to do later in your game and you do it each frame, you’ll bog down on slower devices.  I rarely use 30 FPS.

  1. Here is one example that takes variable frame time into account:

    local cx = display.contentCenterX local cy = display.contentCenterY local cw = display.contentWidth local startX = cw + 100 local endX = 0 - 100 local ch = display.contentHeight local last local bs = 20 – Yes, this is the block size local speed = 100 – 100 pixels per second local getTimer = system.getTimer local lastMove = getTimer() local pieces local onEnterFrame = function( ) local rightmostX = -math.huge local curTime = getTimer() local dt = curTime - lastMove lastMove = curTime local dx = speed * dt / 1000 if( pieces ) then for k,v in pairs( pieces ) do v.x = v.x - dx if( v.x < endX ) then pieces[v] = nil display.remove(v) elseif(v.x>rightmostX) then rightmostX = v.x end end end local tmp if( not pieces ) then pieces = {} tmp = display.newRect( startX + bs, cy, bs, bs) elseif( rightmostX < (startX - bs) ) then tmp = display.newRect( rightmostX + bs, cy, bs, bs) end if( tmp ) then pieces[tmp] = tmp tmp:setStrokeColor(0,1,0) tmp.strokeWidth = 1 end end Runtime:addEventListener( “enterFrame”, onEnterFrame )

  2.  This method uses transition, but I don’t like it much as it can develop gaps due to floating-point errors during placement and synchronization disconnects between transitions and enterFrame events:

    local cx = display.contentCenterX local cy = display.contentCenterY local cw = display.contentWidth local startX = cw + 100 local endX = 0 - 100 local ch = display.contentHeight local last local bs = 20 – Yes, this is the block size local speed = 100 – 100 pixels per second local getTimer = system.getTimer local lastMove = getTimer() local pieces local onEnterFrame = function( ) local rightmostX = -math.huge if( pieces ) then for k,v in pairs( pieces ) do if( v.x < endX ) then pieces[v] = nil display.remove(v) elseif(v.x>rightmostX) then rightmostX = v.x end end end local tmp if( not pieces ) then pieces = {} tmp = display.newRect( startX + bs, cy, bs, bs) elseif( rightmostX < (startX - bs) ) then tmp = display.newRect( rightmostX + bs, cy, bs, bs) end if( tmp ) then tmp.onComplete = function( self ) pieces[self] = nil display.remove(self) end pieces[tmp] = tmp tmp:setStrokeColor(0,1,0) tmp.strokeWidth = 1 local dx = tmp.x - endX local time = 1000 * dx/speed transition.to( tmp, { x = endX, time = time, onComplete = self } ) end end Runtime:addEventListener( “enterFrame”, onEnterFrame )

  3. Here is a physics based solution.  I like this because it better synchronizes with enterFrame(), but I don’t like it because it can make things ‘complicated’ later.  It is also semi-costly. since it uses the physics engine to do the calculations.

    local physics = require “physics” physics.start() local cx = display.contentCenterX local cy = display.contentCenterY local cw = display.contentWidth local startX = cw + 100 local endX = 0 - 100 local ch = display.contentHeight local last local bs = 20 – Yes, this is the block size local speed = 100 – 100 pixels per second local getTimer = system.getTimer local lastMove = getTimer() local pieces local onEnterFrame = function( ) local rightmostX = -math.huge if( pieces ) then for k,v in pairs( pieces ) do if( v.x < endX ) then pieces[v] = nil display.remove(v) elseif(v.x>rightmostX) then rightmostX = v.x end end end local tmp if( not pieces ) then pieces = {} tmp = display.newRect( startX + bs, cy, bs, bs) elseif( rightmostX < (startX - bs) ) then tmp = display.newRect( rightmostX + bs, cy, bs, bs) end if( tmp ) then tmp.onComplete = function( self ) pieces[self] = nil display.remove(self) end pieces[tmp] = tmp tmp:setStrokeColor(0,1,0) tmp.strokeWidth = 1 physics.addBody( tmp, “kinematic” ) tmp.isSensor = true tmp:setLinearVelocity( -speed, 0 ) end end Runtime:addEventListener( “enterFrame”, onEnterFrame )

These all look fairly similar to solutions I’ve tried and I have even tried switching to 30 FPS. Even then, there’s still a slight “jitter” of the objects moving across the screen. I even copy and pasted your initial solution, and the jittering was still occurring, I could tell because the thickness of the stroke lines kept slightly changing. If you can give me a couple of minutes I’ll throw together a quick video capture to help you see what’s going on and edit it into this post.

Unfortunately my screen capture software caused the Corona simulator to slow down considerably and couldn’t really capture what I was talking about, but I found a video from elsewhere that does:

https://www.dropbox.com/s/bn17r80047mh2sv/corona_scroll_test.mp4

If you put it in full screen and look closely at the circle you’ll notice it’s jerking back and forth and not moving along smoothly. This looks far worse when you’re using multiple shapes with distinct edges like Boxes, up against a contrasting background. I wish I could show you how it looks for me but as of right now I don’t have the means.

You can’t rely on the lines looking right.  Try these examples with a complex image.  The lines getting thicker and narrower is a scaling artifact.

Upon further investigation your initial solution does in fact work. I implemented it into my project and in both the simulator and on my phone the game now runs very smoothly.

I guess the key difference here is that my implementation of dt had dt divided by (1000/display.fps.) Yours only divides by 1000 and ditches the fps part from what I can see? And as a result instead of using a scrollSpeed of 3 it had to be adjusted to a much higher number. Perhaps if you could provide comments or a quick explanation regarding the difference here? That’s the biggest difference I’ve spotted, but it definitely works.

A thousand thank yous. This issue was driving me up the wall lol.  :slight_smile:

You’re welcome.  I think the difference you mentioned boils down to:

  1. 1000/display.fps - is  a constant

  2. my dt is variable based on elapsed time since the last frame.

Please note that display.fps never changes.  It is either 30 or 60 based on what was in config.lua.

One more small note.  Recall that I said above, you should always include your code when asking code questions.

I asked this because it allows folks who answer (like myself) to see exactly what assumptions you’ve made.  I wasn’t picking on you.

It is natural to think that ‘my code is fine’ and there is a problem elsewhere, but when you tell me what your code is doing versus showing me your code, this bias covers up the problem.  i.e. If you’d posted the code with ‘1000/display.fps’ I’d have seen the problem immediately.  Then I could have saved time and pointed out the logic error instead of coding three examples.

So, best of luck in your coding endeavors, but remember to post code next time please. 

Hey roaming, as it turns out after extensive testing my game is actually still experiencing major stuttering and performance issues. I see this website doesn’t have a PM feature. Is there somewhere where I can privately contact you and share my project and the code, and have you take a look at it on your end? Maybe do some testing? Just want to make sure this isn’t a problem specific to the devices I’m using at this point.

I may not be able to help you. I’m pretty busy and have to be cautious about doing free work (besides the occasional forums answer).  

That said, I’ll take a peek and if something pops out I’ll let you know either way.

My e-mail is:  rgemail2.png

Just sent the e-mail. Thanks again!