How to call Update in both Child (that inherits from Monobehavior) and GrandChild (that inherits from Child)

I have a class called BaseCharacter that inherits from Monobehavior and a Player class that inherits from BaseCharacter. I want both these classes to call the Update method. Unfortunately, only the Update method of BaseCharacter is being called. I am new to C#, so most likely this has something to do with inheritance. I am not sure if this has anything to do with virtual methods? Below is the code, just to make the situation clearer.

public class BaseCharacter : MonoBehaviour
{
    // Update is called once per frame
    private void Update()
    {
        Debug.Log("calling Update from Child of Monobehavior");
    }
}
public class Player : BaseCharacter
{

    // Update is called once per frame
    private void Update()
    {
        Debug.Log("calling Update from Grand Child of Monobehavior");
    }
}

In the console I only see the message from Player who is the grand child of Monobehavior and not from BaseCharacter who is the child of Monobehavior. I would like to see both messages.

This is where virtual methods come in:

public class BaseCharacter : MonoBehaviour
{
    protected virtual void Update()
    {
        Debug.Log("calling Update from Child of Monobehavior");
    }
}

public class Player : BaseCharacter
{
    protected override void Update()
    {
        Debug.Log("calling Update from Grand Child of Monobehavior");
        base.Update();
    }
}

More information: virtual keyword - C# reference | Microsoft Learn

A lot of this should be covered by basic inheritance tutorials.

1 Like

As a C# newbie you may be tempted to use OOP this way with inheritance. I can tell you I pretty much don’t inherit from MonoBehaviour at all, and specifically not for game logic.

You may want to do some research why inheritance is often the worst choice in designing a game’s code. Unity is already component based, so lean in heavily into that. Consider that whatever makes two BaseCharacter classes differ in behaviour could be implemented by having a Character component, and then either a Player or an Enemy component on the same object. This provides you with greater flexibility, and also avoids using the same codebase where it’s not needed or gets in the way.

Classic trope: EnemyBase - EnemyMelee - EnemyMeleeWithShield - EnemyMeleeWithArrowsAndShieldOmgWhatAmIDoing :wink:

1 Like

Can you maybe describe with code what you mean. I keep hearing that Unity is component-based but I am not even sure what that means. I come from an Android development background and over there it is all interfaces and abstract classes.

Surely you mean, you don’t inherit from types already inherited from monobehaviour?

What’s wrong with that type of inheritance? In my case, the Player inherits from BaseCharacter which itself inherits from MonoBehavior. Other moving objects also inherit from MonoBehavior because they all share the same basic responsibility of moving in one direction. Is there something wrong with this approach?

I mean the point of inheritance should generally be for substitution, which is what polymorphism enables. Namely, if you have an instance where you’re using a base type, the referenced instance should be able to be swapped with any of its derived types while still being able to use it as-is.

In short, IMO, the ‘correct’ use of inheritance is to employ polymorphism to enable substitution.

I wouldn’t use it solely for the sake of reusing code. But I would use inheritance to reuse code in situations where you’re employing polymorphism already.

Though we also have interfaces in C#, which allows you to compose multiple relationships rather than only one, as we can only inherit from one type in C#.

Which is in effect what we do with components. We put multiple on a game object to compose our behaviour and relationships. And worth noting that GetComponent<T> does work with interfaces.

This is all to say that having an inheritance tree can box you in more than it helps.

1 Like

I am curious how would you tackle my specific situation? For me the BaseCharacter simply moves in one direction and checks the health status (if 0, then the object is destroyed). The player that inherits from this then extends it with additional functionality like being able to side step and jump. The Enemy classes that inherit from BaseCharacter add different functionality as well. Some can shoot while others can explode.

Since I cannot replace my BaseCharacter with the Player or Enemy classes (who are originally its children), that violates one of the SOLID principles. But then does that mean I don’t have any inheritance at all and simply define all common behavior in a separate script and get a reference to that and call it whereever I need it? I am already doing that with the different enemy behaviors and defining them using ScriptableObjects that are then provided to each Enemy Prefab. Maybe I should do the same with everything else?

Well the question to ask is: do you have a situation where something else cares about BaseCharacter and its properties (including those expressed by derived types)? Or is BaseCharacter a type that you’re only sub-typing to extend its existing functionality?

If the latter, then there might be no need for inheritance as it isn’t contributing much other than boxing you into an inheritance tree. Or if they have shared properties - particularly simple ones - interfaces might be better.

And simple functions such as ‘move in one direction’ can easily be distilled down into static utility functions that you reuse where needed.

Health, for example, is something that can easily be its own component. It’s a separate responsibility, and can be better encapsulated into its own component. And because you potentially will have situations where you GetComponent<T> for this type, this is a situation where inheritance might make sense, if different entities may have health components that behave differently.

2 Likes

Worth noting that GetComponent<IMyInterface>() works fine. It used to not work in case you ever run into this but that was I don’t know how many years ago (2017 or 2018 perhaps).

When I create something framework-like I follow the best practice that Unity has more recently heavily leaned into, specifically with their cloud service packages. Meaning every class has a public interface and only (or primarily) interface references are being used or exposed.

In case of MonoBehaviours this has the added benefit that to the outside world they can’t just use the MonoBehaviour public methods and, say, Destroy(component) if component is merely an interface.

It came in several phases… GetComponent<I>() was the first one to start working (even as far back as somewhere in Unity5), but GetComponents<I>() and in *Children and in *Parent didn’t… then more of it worked… I’m honestly not sure where things stand right now… every time I reach for getting an interface, I just make a quick test and prove what the API will do for me.

And usually with anything more complicated than a simple GetComponent I wrap it up in something that adds semantic value to my program, such as GetAllBuffableWeapons(); for instance.

I assume that’s what CodeSmile meant too, and I agree. The problem with subclassing below MonoBehaviour so is that no Unity developers EXPECT it, so you always have that surprise friction surface for making lots and lots of irritatingly difficult to track down bugs.

And these bugs can be vastly separated in time and location, triggered by some poor sod just trying to shim in a feature five years down the line, expecting that his OnEnable() will get called, and well, some other sod failed to call base.OnEnable(); but only in one weird variant of a subclass that hardly ever gets used…

2 Likes

Yes, that’s what I meant. I do subclass MonoBehaviour but I don’t build an inheritance tree on top of it.

And of course, if the framework only provides me with an already-subclassed MonoBehaviour, I subclass that. NetworkBehaviour for instance.

Yup, even with NetworkBehaviour the occasional “It won’t work” comes up where it turns out that person subclassed MonoBehaviour instead. I believe there’s also the necessity to call base.OnNetworkDespawn() which is potentially problematic since despawn is rarely used while the commonly used OnNetworkSpawn does not require you to call base. On purpose I nevertheless added base.OnNetworkSpawn() as a reminder.

Oh and then … when do we call base? First thing? Last thing? I’ve even seen code that only worked when base call was somewhere in between because it required the initial setup but then did additional overrides.

2 Likes

That’s why I prefer not to make Unity’s event methods virtual. Instead, I have them call protected abstract methods, similar to hooks in the template method pattern. There’s a hook before the code that needs execution and another one after.

The derived class must implement these hooks, eliminating any temporal coupling. While this approach might occasionally violate the Liskov Substitution Principle because the implementations might be empty, I believe this isn’t problematic for non-public methods.

It is worth it in my opinion because it moves any protentional error to compile time. Anyone deriving from the base class will encounter compile-time errors if they don’t implement the abstract methods, ensuring the code won’t compile until they are while also avoiding any questions of when base code should be called.

Right, that’s one of the most useful features of components :). Though to be more specific the “it used to not work” only applies to the generic version of GetComponent because in the past they put a generic constraint on “T” so it has to be derived from Component. At first glance that seems to make sense but they forgot about interfaces at that time. However the “actual” / underlying GetComponent(System.Type type) always did work with interface types as well. I think the earliest versions I actively tried was Unity3 (released around 2010).

:smiley: Yes, but that would not stop a “bad actor” since you can always cast the reference to MonoBehaviour (if it actually is a MonoBehaviour) and then destroy it or start a coroutine on it. So it’s just like “private” which protects yourself from stupid mistakes but does not really represent a layer of security.

2 Likes

If I am in a situation where I need to hook into the Unity magic methods in derived types, I try do something like this:

public class ExampleBehaviour : MonoBehaviour
{
    private void Awake()
    {
        OnAwake();
    }
    
    protected virtual void OnAwake() { }
    
    private void OnEnable()
    {
        OnEnabled();
    }
    
    protected virtual void OnEnabled() { }
    
    // etc etc
}

I often end up doing the same with IDisposable too. But there are other ways to handle this depending on context. This is generally just the quickest if I don’t need a robust solution.

1 Like

Awwww … that is mean! :grin:

I know for a fact that a junior programmer once spent an entire day hunting down an issue that was due to something like that. It never occured to him to check whether “OnEnabled” never ran, and granted, that wasn’t really obvious. Can’t recall if that was the exact method but it was one of those event methods with a non-obvious typo.

Yeah that wasn’t the best example. Personally I call the methods AwakeInternal, OnEnableInternal though I know that’s not entirely the most ‘correct’ naming convention, but it works for me as a solo dev.

1 Like