How is MonoBehaviour Update() called and how do I implement my own version?

I basically have and update system for my custom static classes running, but I’m trying to improve it.

My example shows how I manage different custom input scenarios (in reality they are different from what Unity offers, so I need my own system).

public class GameController : MonoBehaviour
{
	//find my VirtualInput instance

	void Update()
	{
		//call CustomUpdate() on virtualInput
	}
}

public static InputManager
{
	//create a static instance of VirtualInput class
}

public abstract class VirtualInput : IUpdateable
{
	public abstract void CustomUpdate();
}

public class GamepadInput : VirtualInput
{
	public override void CustomUpdate()
	{
		//update some Gamepad specific events
	}
}

public class KeyboardInput : VirtualInput
{
	public override void CustomUpdate()
	{
		//do nothing
	}
}

So far, everything works, but I wonder how I could design it in a way that gives me the option to implement CustomUpdate() only when I need it. Much like I can write Update() in any MonoBehaviour or just leave it out. Right now, I’m forced to implement it, because this is the way that I know, that the CustomUpdate() will exist, when called from my GameController.

I thought about having the interface IUpdateable only be implemented by those child classes, that need it, but then I would need some kind of reference to them in my GameController, which I think might be a bad idea, because now somebody on my team could make errors by creating instances or using functions, which should be hidden or only acessible through the InputManager class.

Any ideas how to make my system more like the MonoBehaviour Update loop? Thanks!

Unity uses reflection to find the Update methods, but I wouldn’t recommend that for maintainability. There’s a sense that it was a mistake and Unity should have used virtual methods.

“in a way that gives me the option to implement CustomUpdate() only when I need it.”

Use a base class with virtual methods. Make the base virtual implementation do nothing. You could also interface the specific virtual methods, if you really wanted to.

Here’s an example:

public abstract class MyBaseClass
{
    public virtual void MyMethod() {}
}

public class ConcreteClassNoOverride : MyBaseClass
{
}

public class ConcreteClassWithOverride : MyBaseClass
{
    public override void MyMethod()
    {
        // Implementation
    }
}

Hrmm, well you could make the CustomUpdate into a coroutine so that you have to start it in Awake or OnEnable

Actually, yea, OnEnable could work well because then you could also save the IEnumerator and use OnDisable to stop the coroutine. But I’m not sure if that would be needed if it is being disabled. If not, don’t use OnEnable because then you might get multiple coroutines running by accident.

When using yield return null; a coroutine will run every frame; I think it should work fine for input.