Reduce Errors in Mobile Builds
Published 3 years ago
AR or Mobile Builds are Slow Enough without Editor Mistakes

Don't You Hate It When You Wait for the Build Only to Find...

Missing editor settings... or missing components that a script needs... or a missing game object that provides a central control for the game...
But writing all that defensive code in the script gets repetitive. Writing if this is null in Start() and checking that a prefab was set in the public fields of a component. It's the kind of code that adds little value and shouldn't _have_ to be there... but people are people and mobile builds take forever. Forget a setting in the editor and a build is trash.

If Only Defensive Code Were Cleaner

Clean Code is a book written by Robert Martin and it points out some very useful approaches for writing maintainable code. In Melbourne, Australia, many companies hiring software developers demand skills for producing clean code. The results speak for themselves. Defensive code can clutter up a code base and gets pretty noisy, so how to do both?
As I sit here developing for Yubric Reality, I found ways to keep the defensive code simple. I'm sharing that code and other helpful Unity Component bits-n-pieces in a GitHub project called UnityComponents - a really imaginative name - I know....
The project has a namespace called Tools.Common and this has a number of new utility classes. The first one I'll describe is the MonoBehaviourExt that contains extension methods for a MonoBehaviour.
In the examples below, the methods will log (as warning) if the required component reference or editor parameter was not configured correctly in the editor. This log will appear in the Android Monitor, the iOS debug output or in the Editor Console with the prefix of "Unity >" so it is easy to find and filter on.

Checking if MonoBehaviour Fields are Null

Somethings are easier tweaked in the editor so you make public fields (or private with the [SerializeField] attribute) and initialise them to null with the idea that the scene in the editor will set the value. You could check if each were non-null at Start() or Awake() and log errors for each that are, or you can do this.
using UnityEngine; using Tools.Common; public class Foo : MonoBehaviour { public GameObject _CharacterPrefab = null; public GameObject _EnemyPrefab = null; void Start() { this.AreAllEditorValuesConfigured(_CharacterPrefab, _EnemyPrefab); } }
This will log a warning with the name of the variable that is not configured. Note: It uses reflection to determine the missing variable(s) which may or may not work with ILCPP code but you should get a warning at least.
Most of these extension methods also have a variant that use a control variable so you can disable the Update() method if the object is not configured.
using Tools.Common; public class Foo : MonoBehaviour { public GameObject _CharacterPrefab = null; public GameObject _EnemyPrefab = null; private bool _IsReady = true; void Start() { this.AreAllEditorValuesConfigured(ref _IsReady, _CharacterPrefab, _EnemyPrefab); } void Update() { if (_IsReady) { // Do some amazing stuff } } }

Getting Component References Safely

A common thing in a script is to get a reference to another component on the same GameObject but the human designing the scene may have forgotten to add the necessary component. Sure you can use the [RequireComponent] attribute but this also tends to forcibly add the component without any configuration just forcing the problem along. A better solution is to use another extension method.
using Tools.Common; public class MeshModder : MonoBehaviour { private MeshRenderer _Renderer = null; private bool _IsReady = true; void Start() { _Renderer = this.GetComponentOrWarn<MeshRenderer>(ref _IsReady); ModifyMesh(); } private void ModifyMesh() { if (_IsReady) { // Amazing goes here } } }

Getting a Component Reference From Another GameObject

Sometimes you need to wire up components in the scene so they can call each other or setup event handling - like UI buttons.
For this example, let's say there is only one UI button - a 'Go' button - and your scene control component needs a reference to that Button component.
using UnityEngine; using UnityEngine.UI; using Tools.Common; public class SceneController : MonoBehaviour { private Button _GoButton; private bool _IsReady = true; void Start() { _GoButton = this.GetComponentInScene<Button>(ref _IsReady); WireUpGoButton(); } private void WireUpGoButton() { if (_IsReady) { _GoButton.onClick.AddListener(OnGoClicked); } } private void OnGoClicked() { // Load an unbelievable scene!! } }
See how clean that was! Errors don't become exceptions, they become warnings and a quick Play in the Editor will reveal most issues in the scene before we try a build. Methods are short and sweet and the intention is very clear.

Wrapping Up

This little intro into using the UnityComponents extension methods is just a tip in the iceberg. I hope you found it interesting and useful.
All the best for your projects!
Warwick Molloy Lokel Digital Pty Ltd.