Messages are methods with specific names that Unity will automatically call when certain events occur. For example:
public class Example : MonoBehaviour
{
protected void Awake()
{
Debug.Log("Awake was called");
}
}
When an object with that component attached is created (such as when loading a scene or instantiating a copy of a prefab), Unity will automatically call that Awake
method because its name matches the MonoBehaviour.Awake
message.
Receiving a message does not use the override
Keyword like you would for a normal inherited method, you simply declare a method with the appropriate name and parameters (usually none, but check the documentation for the specific message you are receiving) as shown above.
Access Modifiers
In general, most messages should be declared as
protected virtual
.
The rest of this section explains why that's the case and requires a basic understanding of Inheritance.
Don't make them public
Unity doesn't check the method's Access Modifier, which means they don't need to be public
and therefore shouldn't be public
in order to prevent other scripts from calling them unexpectedly while Unity can still call them properly.
The obvious exception to this is if you want to directly call a messasge method from another script. That's not very common, but if you have a good reason for it then you can simply make the method public
.
Definitely don't make them private
private
is actually the worst option for messages because it can lead to your code not getting called if the script is Inherited. For example:
public class BaseClass : MonoBehaviour
{
private bool _IsAwake;
private void Awake()
{
_IsAwake = true;
Debug.Log("BaseClass.Awake");
}
private void Update()
{
Debug.Log(_IsAwake);
}
}
- Unity will never call a script's
Update
before itsAwake
, so if you just look atBaseClass
itsUpdate
method should always logtrue
.
public class ChildClass : BaseClass
{
private void Awake()
{
Debug.Log("ChildClass.Awake");
}
}
- But this
ChildClass
also has a method calledAwake
so if you attach it to an object, Unity will call itsAwake
method and never call theBaseClass.Awake
method. - The
ChildClass
still inherits theUpdate
method though, so now it will logfalse
even though it seems like that shouldn't be possible if you only look at theBaseClass
. - And because
BaseClass.Awake
isprivate
, you can't even call it manually from insideChildClass.Awake
. - This code compiles perfectly fine, but it almost always leads to unintended behaviour. So instead of
private
, you should:
Make them protected
- If you change the methods in the above example to
protected
, then theChildClass.Awake
method will give compiler warning CS0108: 'ChildClass.Awake' hides inherited member 'BaseClass.Awake'.- Even though it's only a warning, that immediately tells you there's something you should fix. Don't just ignore warnings, they exist for a reason.
- The warning message also says "Use the new keyword if hiding was intended", but as described above, having the child method "hide" the base method is generally not the intended behaviour.
- Usually, the intended behaviour is for both
BaseClass.Awake
andChildClass.Awake
to get called, and the correct way to do that is withvirtual
andoverride
like so:
// Make the base methods 'virtual' to indicate that they can be overridden.
public class BaseClass : MonoBehaviour
{
private bool _IsAwake;
protected virtual void Awake()
{
_IsAwake = true;
Debug.Log("BaseClass.Awake");
}
protected virtual void Update()
{
Debug.Log(_IsAwake);
}
}
public class ChildClass : BaseClass
{
// Make the child method 'override' to indicate that it's replacing a base method.
protected override void Awake()
{
// Unity will still only call this child method.
// So if we want both, we need to explicitly call the base method.
base.Awake();
Debug.Log("ChildClass.Awake");
}
}
Normally, calling a virtual
method is slightly slower than calling a regular method because it needs to figure out which method to actually call based on whether the given object is a BaseClass
or a ChildClass
. But that doesn't matter for Unity's messages because it's already doing that anyway, so there's no additional cost for making these methods virtual
.
Common Messages
The MonoBehaviour
page in Unity's API documentation list all of the Messages they can receive, but here are the most common ones:
Message | Called |
---|---|
Awake |
When the object is first created, such as when loading a scene or instantiating a copy of a prefab. |
OnDestroy |
When the object is destroyed, such as when unloading a scene or destroying a single object. |
OnEnable |
Each time the object is enabled (after Awake ). |
OnDisable |
Each time the object is disabled (before OnDestroy ). |
Update |
Every frame while the object is enabled. |
LateUpdate |
Every frame while the object is enabled just like Update , but it happens later in the frame after the animation systems (such as Animancer) have updated. That means this method can be used to overwrite things controlled by animations before the frame actually gets rendered to the screen. |
FixedUpdate |
At a fixed rate which matches the physics system (50 times per second by default). This is good for physics interactions and other mechanics that need to be as consistent as possible rather than being related to the rendering frame rate. |
Reset |
When you first add the component (only in Edit Mode) and when you use the Reset function from its context menu. This is useful for setting up default values that can't be assigned by field initializers and can be useful for Component Referencing. |
OnValidate |
When the component is loaded or any of its values are modified in the Inspector (only in the Unity Editor). This is useful for ensuring that values are valid (such as preventing negative values where they don't make sense) and for Component Referencing. |
Note that when the above table refers to an object being enabled, this requires both the component in question to be Enabled as well as the GameObject
that it is attached to and all of its parent objects to be Active as well. For example, OnDisable
gets called with the component gets disabled or when its GameObject
gets deactivted.
ScriptableObject
s, EditorWindow
s, and various other classes can also receive certain messages.