Messages

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 its Awake, so if you just look at BaseClass its Update method should always log true.
public class ChildClass : BaseClass
{
    private void Awake()
    {
        Debug.Log("ChildClass.Awake");
    }
}
  • But this ChildClass also has a method called Awake so if you attach it to an object, Unity will call its Awake method and never call the BaseClass.Awake method.
  • The ChildClass still inherits the Update method though, so now it will log false even though it seems like that shouldn't be possible if you only look at the BaseClass.
  • And because BaseClass.Awake is private, you can't even call it manually from inside ChildClass.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 the ChildClass.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 and ChildClass.Awake to get called, and the correct way to do that is with virtual and override 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.

ScriptableObjects, EditorWindows, and various other classes can also receive certain messages.