In regards to the comment Bunny83 made about messages requiring virtual to work is incorrect.
Making a function that is soley based off messages virtual is wasteful unless you plan on invoking it without SendMessage – (which should be avoided anyways as its hard to keep up/maintain code that can be invoked multiple ways).
Heres a example of how to override without using virtual.
Entity.cs:
public class Entity : MonoBehaviour {
protected void OnKilled() { print("Entity Has Died"); }
}
Human.cs:
public class Human : Entity {
protected new void OnKilled() { print("Human Has Died"); }
}
Notice the new keyword. The new keyword is basically like a anti-virtual override and makes no expensive virtual call.
So what happens if you were to manually call OnKilled?
static void KillEntity( Entity entity ) { entity.OnKilled(); }
static void KillHuman( Human human ) { human.OnKilled(); }
If you were to pass a instance of Human to KillEntity it would print “Entity Has Died” and if you were to pass that same Human instance to KillHuman it would print “Human Has Died”.
The invocation of methods using the new keyword is entirely dependent on the reference type, not the instance where as virtual and override are instance based.
It’s a bit hard to grasp admittedly but heres where unity messages come in.
Unity messages are invoked through reflection by member name off the type (class) .GetType would return off the instance. So ultimately its completely un-needed to use virtual when you have a function that will only get invoked through send message.
When it comes to using virtual for messages the rules are similar to the new keyword. you can use .base just like you would with a virtual, you need to have the function public, protected, or internal to use .base just as you would as well.
To be clear however, a non virtual method call takes much much less time than a virtual call but we are talking about nano seconds. The reason you should care though is once you get used to using the new keyword for messages you’ll find there is absolutely no reason to use virtual (when dealing with messages ).
So while SendMessage, SendMessageUpwards, BroadcastMessage are VERY VERY slow to use; at least you’ll be able to keep stuff fast once the call stack actually reaches your methods. And it somewhat justifies using SendMessage over C# events when you start talking about very large virtual tables and targeting many game objects at once.
But the most important time to use the new keyword when it comes to OO in unity is in the built-in messages such as Awake, Update, OnDestroy. where you would normally need to mark virtual / override and spend time every frame just invoking off the virtual table, theres no need to. You just use the new keyword.
Another example:
public class Weapon : MonoBehaviour {
protected Renderer[] renderers;
protected void Awake() { renderers = GetComponentsInChildren<Renderer>(); }
public void Hide() { foreach( var r in renderers ) r.enabled = false; }
public void Show() { foreach( var r in renderers ) r.enabled = false; }
//protected void Shoot() { } <-- does nothing. don't need it.
}
public class Launcher : Weapon {
protected ProjectileGenerator projectileGenerator;
protected new void Awake() {
base.Awake();
projectileGenerator = GetComponent<ProjectileGenerator>();
}
protected void Shoot() {
if( projectileGenerator )
projectileGenerator.Eject( transform.position, transform.forward );
}
}
public class Player : MonoBehaviour {
public Weapon weapon;
public void Attack() {
if( weapon )
weapon.SendMessage("Shoot");
}
}
It’s good to understand where you can benefit from the way unity does use messages as it does. things like Awake, Update, Start, OnDestroy should really never be marked as virtual. Personally i avoid using SendMessage at all costs, but there are times when if your sending messages very infrequently it can really simplify code ( as long as you take in mind the possibility for overlaps, and void parameter versus null parameters and your sending messages past Awake or Start where it can be a grab bag of uninitialized badness ).