How to make loading data "smoother" (not creating bottleneck)

Hello everyone,

Im facing following challenge:

I have a game where player sees only part of whole scene.
When player taps button, view of the player changes: objects that are on this new view are loaded and objects that are on current view are removed after view is changed. This works fine.

Only problem is that while objects for new view are loaded, app lags slightly. I would like to load objects more “smoothly” even if this resulted in longer load time. Now, physics and staff just lags while new view objects are being loaded.

Load function iterates indexed table and does something for each iteration (=index of table), depending on object type (sprite animation, spine skeleton, image…), adds listeners etc.

I welcome all tips on how to do this. I would like to have a result when new view objects load for longer time but they dont create bottleneck. Maybe I could use “enterFrame” listener of “timer.performWithDelay” (and load only part of table each frame/timer run)? Is there a better way to do this?

Thank you for reading whole thing.
Jiri

@atanasovskyjiri (Jiri) - You’re on the right track. Use ‘enterFrame()’ or a timer.

If you have a lot of content to create all at once, you can indeed overrun the time allotted in one frame. When you do this, your scripts continue to run and block the SDK from doing other work like processing inputs, animations, physics updates, etc. This is the lag you’re seeing.

To avoid this, you need to split up the loading/creating work into smaller sized bites. One great way to to do that is to (as you guessed) use an ‘enterFrame’ listener to process a queue of ‘work’.

I answered a similar question last year, where a user was trying to do large disk accesses (saves) and was seeing hangs. I answered with a demo showing the problem (blocking) and a solution (non-blocking). It may or may not help, but in case it does, you can find it here:
https://github.com/roaminggamer/RG_FreeStuff/raw/master/AskEd/2019/02/nonBlockingSave.zip

2 Likes

Thank you for your reply.

I noticed that you use timer.performWithDelay( 1, helper ) to restart saving in next frame.

Why is this 1ms timer executed next frame? Can we be certain that it runs exactly next frame?

You can be sure that timer.performWithDelay(1, func) will execute func() the next time the SDK goes to process scripts. e.g. The next frame.

However, you used the word ‘exactly’ and I want to be sure you’re not implying a time constraint. Frame to frame times are not exact. For example at 60 FPS, the time between frame 1 and 2 may be 16ms, while the time between 2 and 3 may be 17ms. Overall the average will be ~16.66, but it isnt guaranteed to be exactly that each time.

At the end of the day treat this code timer.performWithDelay(1, func) as meaning, “Execute func() it the very next frame after this frame, whenever that occurs.”

This pretty much explains what I had in mind.

My concern was that you dont know how much time will pass until the next frame but this time will be definitelly more than 1ms. I wasnt sure if this isnt fired the same frame as next frame is in ~16.66ms (in 60FPS as you explained above). So this timer doesnt fire in 1ms but in ~16.66ms in fact… (probably on deltaTime >= timerTime check in begging of each frame?). Do I understand this right?

People always think of timers incorrectly.

This call performWithDelay( 1000, func ) is not a promise to execute func() in exactly 1000 milliseconds.

It is merely saying that func() will be executed at the first opportunity after (at least) 1000 milliseconds has elapsed.

If that time period elapses in the middle of a frame, func() won’t get executed till the next frame, so the total time will really be: approximately 1000 + <duration of frame when timer elapsed>

As I said above, the trick is timer.performWithDelay( 1, func() ) is saying, “Execute func() it the very next frame after this frame, whenever that occurs.” What really happens is:

  • A timer event with a non-zero time (1 ms) gets queued.
  • This won’t be looked at again till the next cycle when timers are evaluated.
  • When the next cycle comes around about least ~17 or ~33 ms later, that period has elapsed and func() will be called.
  • Tip: 0 delay timers are executed immediately, so you can’t use 0 for this trick.
2 Likes

Awesome. Thank you very much for taking time and explaining!

This is one of the coolest things I learned about Solar in a long time.

You’re welcome. Best of luck on your continuing journey.