Here’s a youtube link if you prefer video formats or want to see it in action.
You wisely didn’t focus too heavily on performance while developing. Here’s the problem: Now, you launched your game on a new, weaker platform (Android, iOS, or perhaps Switch). Or maybe this is your first launch, and you’ve only ever tested on a beefy PC. You find your game is laggy beyond what’s comfortable for people. What to do!?
When you solve your performance problem, please comment on how you solved your problem below. Let’s all help others spend less time on these issues.
Unity to the Rescue!
Profile Tutorial
To help you see when the game gets slow, show your FPS while playing. Click the stats button in the Game menu:
Now for the fun part! Open the profiler in Window > Analysis > Profiler (Ctrl+7)
Explaining the profiler page:
Your CPU Usage shows you the FPS over time. Many sections here can show you if Rendering, Audio, Memory, etc. could be problems.
The timeline shows your current frame and how much time each script takes to run. Sometimes you can easily see the name of the script (Purple or Blue ones are ones that are yours, usually) and that’s a dead giveaway that it’s probably taking too long.
I prefer the Hierarchy view myself. You can sort by how many milliseconds each script takes to run and see exactly which script is causing you problems:
Common Causes and Fixes:
- Garbage Collection: Optimize it
- Calling GameObject.Instantiate for repetitive objects:
- Here’s a free Asset that does Object Pooling for you: Lean Pool. Pooling will reuse objects you’ve despawned instead of making new ones. Lean Pool is dead simple. Simply change Instantiate to Spawn and Destroy to Despawn. I love it and it’s free!
- Using GetObjectByType too much, especially in Update methods.
- Consider passing in variables via the Inspector ([SerializeField] private members) or other dependency injection frameworks.
- Only GetObjectByType, Find, GetComponent, etc during OnEnable, Start, or Awake.
- Instantiating too many objects with “new” in Update loops
- Create them on Awake or Start instead.
Please comment on how you solved your performance problem below. Let’s help other people make it easy to fix these problems, so we get better quality games faster 🙂
My Example
Here’s a youtube link if you want to see me use the profiler in action to solve my problem.
After using the profiler, I discovered this script was taking 3 ms in Update (even on my beefy desktop).
public class EffectPerformer : MonoBehaviour {
void Update () {
foreach (Effect effect in Resources.FindObjectsOfTypeAll(typeof(Effect)) as Effect[]) {
effect.performEffectOverTime(Time.deltaTime);
}
}
}
So what’s the problem? Maybe there are millions of effects? Nope, just 100. Maybe performEffectOverTime is expensive? Nah, they should all be simple math calculations.
The problem is in the foreach loop definition! Every update, it creates a new array of Effects that are found via Resources FindObjectsOfTypeAll. Both of these operations are expensive (especially the first one).
Here’s what I did:
public class EffectPerformer : MonoBehaviour {
private Effect[] effects;
void Start() {
effects = Resources.FindObjectsOfTypeAll(typeof(Effect)) as Effect[];
}
void Update () {
foreach (Effect effect in effects) {
effect.performEffectOverTime(Time.deltaTime);
}
}
}
The solution is to cache the effects on Start. In this case, I know there will never be more effects added (and if the list could change, I would pass the effects in via dependency injection, so another script could update the list) so everything works well now:
Now we’re moving so fast that Unity has to wait to reach my target 120 FPS! Great!
Notice how simple it was to figure this out. I made a simple mistake because when I wrote this, I was naive about Unity. But, if I started over-optimizing I could’ve created some complex algorithm to bucket effect calculations into different frames, but that would be bug heaven and a readability nightmare- all to realize IT WOULDNT FIX ANYTHING! It’s better to wait to see what your performance bottlenecks will be before over-optimization.
I had a problem activating and deactivating game objects too frequently. I found that it’s better just to move their transforms far away.