General strategy for improving input delay

Lately I have been working with a tilemap that’s roughly 3000px * 2000px in size, and while my app is running at solid 60fps and with a lower memory usage (both system and texture are lower than 15MB), I see a noticeable delay (or lag) when I try to pan the map.

My tilemap renderer and controller does something like following:

  1. cache tilesets.

  2. start rendering the first layer, put all tiles in a display group ( layer1 )

  3. when done, start rendering the second layer and so on ( layerX ).

  4. when all layers are done, put layers in the a display group ( map ).

  5. when user hold and move, pan the map (display group).

I didn’t do manual culling or other optimization yet, just wondering, what could have cause the lag? I see no noticeable delay on smaller map (say 600px * 600px).

Although your question is very clear, there is not nearly enough detail here for me (or likely anyone else) to try to help with this. What framework are you using for the tilemap? Can you provide some sample code? Based on your description, there could be a plethora of reasons for such a lag.

Yeah you are right, I should provide more details:

  • To be honest I think it has less to do with my code (I wrote my own tilemap renderer, I need a simpler and custom solution);

  • But rather I got a large display group with many (thousands) small display objects (tiles), is there anything I should do before I move the display group by setting {x,y} value?

  • Since I use touch event at  60fps , I can clearly see slowdown in event.time (20+ms instead of 16ms, and map panning lags behind my mouse movement).

  • Yet display.fps remains at solid 60fps , so I am also wondering if I should measure performance differently.

My code looks something like this:

function MapControl:touch (event) --print(event.time) if event.phase == 'began' then self.camera\_panning = true self.ox, self.oy = self:getCamera() elseif event.phase == 'moved' and self.camera\_panning == true then self:setCamera( self.ox - event.x + event.xStart , self.oy - event.y + event.yStart ) elseif event.phase == 'ended' or event.phase == 'cancalled' then self.camera\_panning = false end end

As far as the lag. You may actually get better performance by dynamically adding/removing tiles as the map pans. The work required to move all of those elements likely outweighs the cost of re-drawing at this point.

display.fps shows your configured framerate. Not what the game is running at. You need to find your frame delay with system.getTimer(). (1000/delay) will give you your FPS.

Sloppy mock-up:

local lastTime,totalTime,tickCounter,avgTime,avgFPS = 0,0,0,0,0 function enterFrameFunc() local thisTime = system.getTimer() local thisDelay = thisTime-lastTime --Timer will be off for the first count because lastTime has no value totalTime = totalTime+thisDelay tickCounter = tickCounter+1 if tickCounter \> 5 then avgTime,avgFPS = totalTime/tickCounter, 1000/(totalTime/tickCounter) fpsDisplay.text = "FPS: " .. math.round(avgFPS\*100)\*.01 .. " - Delay: " .. math.round(avgTime\*100)\*.01 tickCounter,totalTime = 0,0 end lastTime = thisTime end

@txzeenath you are right. I have corrected my FPS counter since then and find it drops down to 40-50 fps on my Macbook Air when I pan the map.

@all since Corona SDK already did some offscreen culling automatically, any in depth guide on how to improve draw batching for tilemap rendering? should I culling manually?

my tileset should be pretty compact at this point, so I am not sure what else I could do just by looking at the optimization guide.

You could narrow the lag down to what function causes it by putting delay checkers inbetween code

start = system.getTimer()

–~20 lines later

print(system.getTimer()-start)

If it is a large delay then you know it’s somewhere in the 20 lines and you can keep narrowing it down.

just a hacky suggestion

Although your question is very clear, there is not nearly enough detail here for me (or likely anyone else) to try to help with this. What framework are you using for the tilemap? Can you provide some sample code? Based on your description, there could be a plethora of reasons for such a lag.

Yeah you are right, I should provide more details:

  • To be honest I think it has less to do with my code (I wrote my own tilemap renderer, I need a simpler and custom solution);

  • But rather I got a large display group with many (thousands) small display objects (tiles), is there anything I should do before I move the display group by setting {x,y} value?

  • Since I use touch event at  60fps , I can clearly see slowdown in event.time (20+ms instead of 16ms, and map panning lags behind my mouse movement).

  • Yet display.fps remains at solid 60fps , so I am also wondering if I should measure performance differently.

My code looks something like this:

function MapControl:touch (event) --print(event.time) if event.phase == 'began' then self.camera\_panning = true self.ox, self.oy = self:getCamera() elseif event.phase == 'moved' and self.camera\_panning == true then self:setCamera( self.ox - event.x + event.xStart , self.oy - event.y + event.yStart ) elseif event.phase == 'ended' or event.phase == 'cancalled' then self.camera\_panning = false end end

As far as the lag. You may actually get better performance by dynamically adding/removing tiles as the map pans. The work required to move all of those elements likely outweighs the cost of re-drawing at this point.

display.fps shows your configured framerate. Not what the game is running at. You need to find your frame delay with system.getTimer(). (1000/delay) will give you your FPS.

Sloppy mock-up:

local lastTime,totalTime,tickCounter,avgTime,avgFPS = 0,0,0,0,0 function enterFrameFunc() local thisTime = system.getTimer() local thisDelay = thisTime-lastTime --Timer will be off for the first count because lastTime has no value totalTime = totalTime+thisDelay tickCounter = tickCounter+1 if tickCounter \> 5 then avgTime,avgFPS = totalTime/tickCounter, 1000/(totalTime/tickCounter) fpsDisplay.text = "FPS: " .. math.round(avgFPS\*100)\*.01 .. " - Delay: " .. math.round(avgTime\*100)\*.01 tickCounter,totalTime = 0,0 end lastTime = thisTime end

@txzeenath you are right. I have corrected my FPS counter since then and find it drops down to 40-50 fps on my Macbook Air when I pan the map.

@all since Corona SDK already did some offscreen culling automatically, any in depth guide on how to improve draw batching for tilemap rendering? should I culling manually?

my tileset should be pretty compact at this point, so I am not sure what else I could do just by looking at the optimization guide.

You could narrow the lag down to what function causes it by putting delay checkers inbetween code

start = system.getTimer()

–~20 lines later

print(system.getTimer()-start)

If it is a large delay then you know it’s somewhere in the 20 lines and you can keep narrowing it down.

just a hacky suggestion