How to reduce code complexity and boost performance in Unity



Building a 3D, physics-based game such as Mars Commander can be a daunting task indeed, even in an indie-friendly engine such as Unity. Yet what cost us the most in terms of time was not so much coding the game up as it was streamlining the game to keep its codebase maintainable. 

This time-consuming process was nevertheless necessary or we would have gotten completely lost along the way, and our demo would have never come out. 

Here are two rules that we learned along the way. 

1) Prevent direct method calls wherever possible

As an experienced web developer, I’ve seen some pretty complex codebase, but nothing in web development comes close to the bewildering complexity of modern 3D video games. In the case of Mars Commander, for example, we have weapons, projectiles, vehicles, vehicle movement, vehicle physics, enemies, AI, AI squad formation, scene transitions, and much, much more. All these elements need to be both coded up and managed, meaning heaps and heaps of GameObject-altering scripts. 

As a developer, because of this complexity, you want to make your development experience as smooth as possible. There are undoubtedly many ways to do this, but in the case of Mars Commander, we chose to avoid direct method calls wherever possible. 

If we hadn’t taken this approach, we would have had cross references between scripts everywhere, leading to unmanageable code, and a buggy, impossible-to-finish project.

We chose C# events as the main alternative to such direct references. Events are occurrences inside a game such as weapons that fire, vehicles that move, and levels that have finished loading. Events aren’t really predefined in any way by Unity, meaning that we as developers have an amazing degree of freedom in how we decide to both declare and use them. 

More on events: https://www.youtube.com/watch?v=k4JlFxPcqlg

Using events over direct method calls requires a slightly different mindset, but events are an amazing tool for maintaining optimized, clean codebases. We use them all over the place, and are quite happy with the result.

2) Use direct method calls where speed is essential

Yes, this rule in many ways contradicts the first, but it has helped us greatly boost our codebase’s performance. While C# events are reasonably fast, nothing will ever beat the speed of a direct method call. Therefore, when coding up a pathway where speed is essential, use direct methods calls. 

In Unity, obvious use cases for these are Update, and FixedUpdate, which are methods that automatically update every frame and 50 times per second respectively. For example, in Mars Commander, all player units hover, and this mechanism is completely physics-based, meaning that its code is executed in the aforementioned FixedUpdate. We did indeed use C# events initially, but this simply wasn’t fast enough, as Unity’s performance monitoring tool showed us. Direct method calls fared much better.

Another example of such a critical codepath would be enemy AI as it needs to be updated in the same manner as well. Again, we were able to extract more performance by reverting to direct method calls.

Granted, the above considerations may not be important for all project types, as the most resource-heavy component of games is usually graphics. However, for games such as Mars Commander, where physics play an important role, or for RTS games, where hundreds of units could be moving and duking it out at once, these types of optimizations may well be what saves your game.

Of course, we learnt many other rules and lessons along the way, and we may indeed share these in a future article. For now, these two tips should offer you a glimpse of how we managed to optimize our game.

Get Mars Commander

Leave a comment

Log in with itch.io to leave a comment.