-
Notifications
You must be signed in to change notification settings - Fork 0
Helpful Tips
This page is to act as a knowledge-base of useful tips and tricks that may be unknown to other project contributors.
If you have a function that you want to have multiple outputs from, you can output multiple values without needing a new type to encapsulate everything within a single return value or the use of something like tuples.
C# and Unity support the use of out
parameters within method signatures
Below I have listed several common and useful functions that can be overridden within MonoBehaviour classes along with a brief bit of information about each. Note that all of these methods should have protected
scope.
Function | Description |
---|---|
Start | Called on the first frame that the object is enabled. This function will only be called once per object per scene load. This will execute before any call to Update() . |
Update | Called every frame when the MonoBehaviour instance is enabled. |
Awake | Called when the MonoBehaviour instance is first loading in. This is called before Start() and executes regardless of if the behavior is enabled. |
FixedUpdate | An update method called at a fixed frame-rate, generally used for calculations like physics that rely on consistency time intervals between calls. This may occur multiple times per frame. |
LateUpdate | Called at the end of each frame similarly to Update() , but all calls to Update() will have already completed for all objects. |
OnEnable | Called any time that the MonoBeaviour or its owning object becomes enabled. If the object should be subscribed to any delegates or events they should be re-subscribed to here. |
OnDisable | Called any time that the MonoBeaviour or its owning object becomes disabled. If the object is subscribed to any delegates or events they should be unsubscribed here. |
OnDestroy | Called when the MonoBehaviour instance or its owning object are destroyed. This is an ideal location for cleanup code. |
For a mush more in-depth description of the life-cycle of a MonoBehaviour instance please see Unity's Documentation on Event Functions
To achieve smooth movements or calculations within Update()
, you can multiply your values by Time.deltaTime
which is the time that has passed between frames. This will ensure that your calculations are done based on real-time elapsed instead of frames. Note that behaviors inside of FixedUpdate()
do not require this type of smoothing due to the fixed time interval between calls.
If you need a collection of data and behaviors that would benefit from existing as a standalone asset in the project that can be repeatedly referenced, you will likely want to use a ScriptableObject
. Examples of their use cases are creating item assets, creating abilities, creating enemy types, creating settings presets, and creating dialogues among many other things. For more information see the Unity Documentation.
If there is any editor only code mixed in with runtime code, you can strip out the editor code during non-editor builds by using preprocess directives. The needed directive is #if UNITY_EDITOR
An example of this can be seen in BuildABot.Utility.QuitGame()
:
public static void QuitGame(int exitCode, string message = null)
{
#if UNITY_EDITOR
EditorApplication.isPlaying = false;
if (exitCode != 0)
{
if (message == null) Debug.LogWarningFormat("Play in editor exited with code {0}", exitCode);
else Debug.LogWarningFormat("Play in editor exited with code {0}: {1}", exitCode, message);
}
else Debug.Log("Play in editor exited with code 0");
#else
Application.Quit(exitCode);
#endif
}
Coroutines are functions that can be executed over the course of several frames. Any MonoBehaviour
can call StartCoroutine
which takes in a function that returns the type IEnumerator
, which acts as a type of handle for the behavior. StartCoroutine
will begin execution of the function, which will continue until finished normally or forced to stop by StopCoroutine
(which takes in the IEnumerator
) returned by the function earlier.
This is a fairly large topic, so it may be helpful to look through the Unity Documentation for Coroutines.
As a convenience, the BuildABot.Utility
class includes a wrapper for a WaitForSeconds
coroutine called DelayedFunction
which will execute a specified function after a given number of seconds. For simple delayed behaviors, this should be preferred over setting up new coroutines from scratch each time.
Some specific types of delays used in Coroutines can be seen here.
In cases where you need to choose between two potential values based on a condition, instead of writing a verbose if else statement such as:
if (someCondition) result = valueA;
else result = valueB;
You can instead write that expression in a single line using the ternary (?:
) operator like so:
var result = someCondition ? valueA : valueB;
The general form of the ternary operator is as follows:
condition ? valueA : valueB
where the expression evaluates to valueA
if condition
is true, or valueB
if condition
is false.
While a bit less straightforward to read than if-else statements when you are not familiar with them, this allows for inlining of conditional behavior and can even be nested for multiple conditions.
When accessing a member field, property, or method of an object, we can use ?.
to check if the accessed object is null. The form of this operator is:
myObject?.someMethod()
If myObject
is valid, the expression will evaluate like normal. If myValue
is null
, then the expression evaluates to null
.
This same type of syntax can also be applied to array access:
myArray?[index]
For more information see the Microsoft C# Documentation.
WARNING: While these operators (?.
and ?[]
) are very useful for C# types, be careful using this for Unity types such as MonoBehaviours or GameObjects due to some internal implementation details of Unity Objects.
In a similar vein to the ternary operator, C# supports a null-coalesing operator ??
in the form value ?? otherValue
where the operator checks if value
is null
before selecting the value of the expression. If value
is not null
then the expression evaluates to value
, otherwise it evaluates to otherValue
.
This is the equivalent of (null == value) ? value : otherValue
.
Similarly, an assignment version of this operator exists value ??= otherValue
where value
will only be assigned the value otherValue
if value
is null
. This is equivalent to if (null == value) value = otherValue;
WARNING: While these operators (??
and ??=
) are very useful for C# types, be careful using this for Unity types such as MonoBehaviours or GameObjects due to some internal implementation details of Unity Objects.