3 Ways to Reduce Load Time in Runtime for Unity

Long loading time have always been a problem for most indie games. With my experience in game development, I can assure that if you don’t pay attention and avoid it, it will eventually become the bottleneck of your game’s performance. I’ll list 3 reasons that might slow down game loading and show you how does SmartReference(https://github.com/Brian-Jiang/SmartReference) make your game loads 10x faster.

Do not use Resources folder to store all your assets

Most beginners store assets in Resources folder and load assets using Resources.Load API call. This is convenient but the problem is when you load any assets in Resources, unity will load the whole Resources bundle, which basically means that all assets of your game will be loaded from the launch of your game. This terrible and is usually the reason that your game startup slowly.

Another thing I want to point out is that scenes are automatically included in resources, as for everything it references. So if you never think of asset management but your game can still work, that might be the reason. However, when your game grow, you’ll find asset management neccessary to keep expanding your content.

To resolve this issue, avoid using resources. Instead use asset bundle or addressable to organize your assets. Pure asset bundle is harder to manage and requires more programming skills, but you can get full control of your assets. Addressable, on the other hand, is built on top of asset bundle and simplifies the workflow, therefore I have been using addressable for my games. Check out manual on how to use it: https://docs.unity3d.com/Packages/com.unity.addressables@1.21/manual/index.html

Only load what you need and don’t forget to release them

In your game logic, do not load everything in start function, you can control which asset to load when player go through the level. The implementation is highly related to your game mechanics so it’s hard to give a general solution, but you can follow these rules:

  • If your game is level based, make sure you know what the level should load and release unused assets when player finish one level by calling Resources.UnloadUnusedAssets
  • If your game is not level based, make sure there are times where assets unloading happen
  • Profile your game using MemoryProfiler, it shows how your game uses memory. Profiler window is also helpful, it can display whether memory usage is keep going up with time

Reduce dependency for your assets

This is usually a trap if you don’t handle it carefully and it once confused me for some time. Imagine that you use Scriptable Object to store data for your game. There is a class called Monster and it contains name, description, icon sprite, maxHp, 3d model, attack and defense. There are probably a total of 100 monsters and stores in 100 SO files respectively. Let’s say you want to get all names and descriptions of monsters, how long do you think it will take to load all 100 files? The result might be surprising if you test it. It will actually load 100 SO files, 100 sprite icon, 100 prefabs for models, 100 meshes, 100 or more materials, all shaders used for these materials, 100 textures used in material, more textures if have normal map or other maps. These are the dependencies of monster SO files. Besides, if you have your own MonoBehaviours attached to the prefab and it reference other assets, all of them and their dependencies will load as well. One more bad new is that when unity load asset, it loads the asset bundle which may contain other assets depending on how you organize. That’s a whole bunch of memory and time taken just to load names and descriptions of all monsters.

The solution to this problem is straight forward: do not directly reference sprite and prefab in monster SO files. So how can you indirectly reference a prefab? The best way is to store path of the prefab and load prefab using path at runtime. With some editor code and runtime setup, it is possible to have exactly same workflow as direct referencing. The SmartReference package I mentioned ealier does exactly this. When you reference an asset, unity will serialize it like this and treat it as the dependency

Unity’s default reference

If you use SmartReference, it will instead serialize to this

SmartReference uses path instead of direct reference

The guid, fileID, and type are all for editor use, the path property is what actually used in runtime. When you try to access the property, it will first load the asset at that path and then return it. The only thing you need to care is setting up load function when your game start. Now if you want to load 100 names and descriptions, only 100 SO files would be load. If later you want model as well, it will also load properly when you explicitly access them.

To conclude, you NEED to take care asset management in your game, any serious developer will consider it an important aspect. You can start by switch from Resources folder to addressable, profile your game and make sure unloading assets is include in the logic. Eventually, use SmartReference instead of direct referencing to prevent loading unused dependencies. With these practices, you can take your game quality to the next level.


Posted

in

by

Comments

Leave a comment