Search code examples
iosmemoryassets2d-games

Game asset loading strategy for smooth ux


I am working on an image / text based story game. Not using anything specific for it, jut a lot of ui components that rely on background images / image elements.

One of the bottlenecks for me right now are screens that include many images (not scrollable views, just screens with many bitmaps).

On some prev gen devices you can clearly see some images that take about .2s to .4s to appear on a screen. I assume this is bottleneck of loading many images from disc.

I solved this issue by preloading images into memory, now everything is there without delays.

I'm not sure if this is the best solution, but it seems like many games are doing something similar (i.e all these game loading screens)?

Hence the question. Is this the way or is there a better one to preload game assets?


Solution

  • One strategy, is loading all of your assets in one go at the beginning. If you only need to tradeoff just a couple of secs to load everything, in return for a fast and seamless gameplay experience from there on in, that's the biggest bang for your buck.

    Just keep an eye on your app's memory footprint. The system will terminate your app in the middle of preloading if it takes up too much memory. For iPhone 6 I remember that threshold was around 500MB. Not sure if this is device specific. Also, even if you are able to preload all of your game's assets at once, if it is too close to the threshold, the act of the user opening even a lightweight app can cause the system to terminate your app to free up memory. So when they switch back to your game, it will need to preload everything again.

    Eventually though, as your game gets bigger and uses more assets, preloading everything at once will no longer be an option, as your app would be terminated in the middle of that process.

    When it gets to that, you'd need to pick points to partition your gameplay, for example, a start, middle and end: A, B, C. So when you start the game, only A's assets are preloaded, and then somewhere between A and B, you trigger the preloading of B's assets in the background. And once B is reached, you remove the references for A's assets, causing that memory to be freed.

    With that, your overall memory footprint is smaller, and you reduce the initial loading time to start playing the game. The first strategy of preloading everything was essentially partitioning your gameplay into 1 part. With more partitions you improve that efficiency.

    But in light of doing things lazily, I would cross that bridge once you get to it, because I would say that a good game with a suboptimal asset preloading mechanism is still far better than a so-so game with a really good asset preloading mechanism.

    An efficient strategy will depend on the nature of your game, but the gist is to load what you will need, before you need it. And to free the memory of things you no longer need. A game that has discrete levels is typically easiest to do this for, as you can preload just that level's assets, then when the level is over, free that memory and load the next level's assets while you show a loading screen. Or if your game is continuous, you can partition it into stages and have each stage keep references to the assets it uses. So if A and B shared some assets, removing A's asset references won't free memory of assets that B still has references for. And if your gameplay allows the user to move backwards as well, like going back to A after reaching B, then instead of freeing all of A's assets once B is reached, perhaps you only free the first half of A. Things can get complicated with these moving buffer designs too because perhaps all of A uses the same assets throughout.

    Also, if your game has a lot of little assets, it's supposed to be more efficient to put them all into a texture atlas and preload the texture atlas instead of all the individual assets (See SKTextureAtlas in SpriteKit).