Class General:MonoBehaviour
{
Awake() { zzz }; // incidentally, how to "sealed" this?
Start() { aaa }
Update() { bbb }
}
Class Foo:Base
{
Start() { ccc }
Update() { ddd }
}
Say the behavior you want is, that BOTH (!) the base and derived functions run, when you call the function on an instance of Foo.
Of course: you can do this with the keyword base by calling base.Start() in the derived, or quite simply your team of programmers can socially agree to have another function like “SecondStart()” in the derived which you agree is always called by General.Start() if it exists.
But the question here is: is there a way, in c# to flag Base with the concept: “if there’s a derived function, call both (!!) of us.” In contrast to the usual OO operations.
(Or conceivably, there may be some similar exceptionalism in MonoBehaviour for this in the case of Start, Awake specifically?)
That’s actually basic OOP. If you declare a method as virtual you can override it in a derived class which will replace the original method. The new method is responsable for calling the base method or not by using base.Start / base.Update.
If you want to create some kind of “framework” you might want to define new methods which the user can override / declare:
public class FrameworkBase : MonoBehaviour
{
private void Start()
{
// do something
Init();
// do something else
}
private void Update()
{
// do something
Think();
// do something else
}
public virtual Init() { }
public virtual void think() { }
}
In a derived class the user can override “Think” and “Init”
public class Derived : FrameworkBase
{
public override Init()
{
// user stuff
}
public override void think()
{
// user stuff
}
}
that way when the user overrides the functions it doesn’t matter if he calls the base function or not.
Note:
Of course the user has to override the function, hiding doesn’t work since hiding is actually breaking the OOP concept. However if you want to allow this you can implement the dispatch with SendMessage like this:
// in the base class:
private void Update()
{
SendMessage("Think", SendMessageOptions.DontRequireReceiver);
}
That way the user can declare a “Think” method just like you usually can declare the Update function.
Additional Note:
Of course the user must not declare and Update or Start method in thie case since that would break this concept.
using UnityEngine;
using System.Collections;
using System.Threading;
public abstract class StealthyBaseClass : MonoBehaviour
{
private int counter = 0;
public StealthyBaseClass ()
{
Thread newThread = new Thread(new ThreadStart(Start));
newThread.Start();
}
void Start ()
{
//We need to wait here for this object to become properly serialized.
//There might be a way to tell... Further research needed.
Thread.Sleep(100);
Debug.Log("Base class Start called without explicitly called.");
counter = 30;
}
}
As you notice, it uses the constructor and other threads, both of which are a pretty big no-no in Unity. So use at your own risk.
This code is dangerous for several reasons:
Constructors in MonoBehaviours can be called multiple times in the Editor, at possibly random times.
The Unity API is not thread-safe, using your own threads can (and did…) freeze Unity and cause other unforseen results.
This is the base class from which other developers need to derive from. When a new derived class is created (or in the case of MonoBehaviours, added to a GameObject) the constructor of the base class is also called. In my tests, it called the constructor (and Start) twice when pressing Play.The class need not be abstract, however, if this class were to be added to a GameObject, Unity would call Start a third time.
So, as an example, if :
public class ExtendedClass : StealthyBaseClass{
void Start(){
Debug.Log("Extended class Start");
}
}
is added to a GameObject, both Start methods would run. I suspect the extended Start first, because 100 milliseconds is a long time to wait in the computer world. The order could be different, depending on how fast the machine is… Furthermore, it cannot be guaranteed that the Start of StealthyBaseClass is called before the next Update, as with normal Start methods.
TL;DR: whenever a class derived from StealthyBaseClass is created, the Start of StealthyBaseClass is called. Should the derived class have a Start method, that will be called too.