Original article in the TGC Newsletter can be viewed here
In our last game, Shape Time, I ended up deciding to load quite a few assets at launch time. I implemented a loading animation, but it seemed to actually slow down the loading process a bit. In our next game I wanted to optimize this as much as possible to improve loading time. The reason the loading animation was affecting the speed of loading assets was that I was calling Sync() as frequently as possible so that the animation would update. Here’s an example how it was done (the loading animation in this case is a sprite with frames):
This would certainly animate the loading sprite just fine, but I knew there had to be a better, more universal way. The problem is that Sync() is limited by the frame rate of the device. So if you’ve got a device that is capable of only 30FPS (fairly common in with mobile devices) then you are limiting your loading sequence to one file every 30th of a second. This is not that bad for files, but if you want to display the animation while other, possibly faster processes take place, then you’re likely slowing them down.
Let’s look at an example of a script that might be slowed by a Sync() call:
This script is pretty fast, but it might take up to a second or more on mobile devices. If we add a Sync() call to this routine so we can show a loading animation then the routine will be much slower because the Sync() call will render the screen and limit the engine to whatever the available FPS is. At 30FPS this script would require 3.33 seconds to run. Without Sync() it may take considerably less time, however, that would be dependent the device.
So how do we speed this up? The answer is to only call Sync() only when it is time that you expect to have a frame drawn to the screen. The example below uses a literal 1/60 of a second between Sync() calls. There are more advance ways to determine the expected time to call Sync(), but this is sufficient for showing a loading animation. The example simply rotates a loading image for simplicity.
The code consists of 2 globals and 2 simple functions. ToggleLoadingAnim() is used to set up the sprite and globals, position the sprite, and make it visible. This should be called before any loop that you want to overlay the loading animation on. You also call this to hide the animation. Inside of the loop you will use LoadingAnim_Sync() in place of a standard Sync() call. So our original code that loaded 100 sprites becomes this:
That’s it! Now you can load up lots of assets and have a nice loading animation so that the user doesn’t wonder what’s going on. Remember, folks don’t like to wait even a second for something to happen these days, so make sure to use a method like this to let them know your game is still running. Now if we could only thread the loading animation so that we can draw to the screen while loading large files. Another thing you might want to consider is that you might get large values out of GetFrameTime() while loading files. So you might want to limit the ft# variable when you’re translating a sprite (moving or rotating). Either way you’ll get a bit of jitter in your sprite’s translation because Sync() just can’t be called fast enough due to the time it took to load a file.
Users don’t want to wait long for your game to load, so it’s important to only load at launch time the assets you need to display the title screen / main menu of your game. After that you can stagger the creation of assets by creating only a handful every frame and then if they aren’t all loaded when they’re actually needed, you can finish up loading them and show a loading animation. In our next game I did this for our level selection menu.
The level selection menu needed 200 buttons, 3 star sprites for each button, and 2 text objects for each button – that’s a total of 800 sprites and 400 text objects! This was just way too slow to load on demand. So what I did is create a handful of these objects every frame during the Sync() calls. This way the buttons could be loaded while the player is looking at the main menu which incorporates a short animation of about 2 seconds. Let’s examine how we can do something like this.
Make an array that will hold the object IDs for the level buttons and a global to hold an image ID:
Create a new function that includes the Sync() command and will create a handful of objects each frame:
Now we’re creating those 200 sprites in 20 frames. At 30FPS we’ll have created them in less than 1 second! They should all be prepared by the time we need to show the level selection menu, but just in case, you should also have a catch that ensures they’re all created when the user goes to access the level selection screen. If they aren’t all made then you can show the loading animation to tell the user the app is working on something.
This method can be used in a variety of ways. For example, while the user is playing one level you can slowly start loading the assets for the next level in each frame. This should be done with care so that it doesn’t drag down performance when the action of the game is happening. As long as the sprites are off-screen they won’t be rendered and won’t cause a drag on the engine.
Next time I’ll discuss methods on how to “thread” animations in a loop so that you can easily contain different animations in separate functions. Oftentimes we need to have a lot of things going on simultaneously and they cannot interrupt each other or user input. Thanks for reading!