Initialize inherited class member in inherited class

Hello all,

My classes:

[System.Serializable]
public class AgentLocomotion
{ ... }

[System.Serializable]
public class ChaseLocomotion : AgentLocomotion
{ ... }

[System.Serializable, SelectionBase]
public class Mob : MonoBehaviour
{
    [SerializeField] protected AgentLocomotion[] entityLocomotions = new AgentLocomotion[] { new AgentLocomotion() };
    public int entityLocomotionID { get; protected set; }
    public virtual AgentLocomotion entityLocomotion { get; protected set; }
}

[System.Serializable, SelectionBase]
public class Monster : Mob
{
    [SerializeField] protected ChaseLocomotion[] chaseLocomotions = new ChaseLocomotion[] { new ChaseLocomotion() };
    public virtual ChaseLocomotion chaseLocomotion { get; protected set; }
}

I’d like to avoid to create chaseLocomotions-array in Monster-class, instead is there a way to change the array initializer

new AgentLocomotion()

// to

new ChaseLocomotion()

Is there another solution to ScriptableObjects, so it is defined by class and not need to be manually set by editor? Maybe a complete different approach, which isn’t too complex?

You could compose these various aspects through interfaces.

Also remember Unity is component based. This inheritance based approach generally doesn’t gel with Unity and games in general.

No, you can’t write AgentLocomotion[ ] entityLocomotions = new ChaseLocomotion[0]; that’s not valid. But you can populate the array with ChaseLocomotion, this has nothing to do with the array initializer tho.
And when you add ChaseLocomotion to your ChaseLocomotion[ ] array, unity will not serialize it. It might work when using [SerializeReference] but you’d need a custom inspector to add those classes.
Also … you have to cast to ChaseLocomotion every single time you access the array. Why would you even write it this way?

Why use inheritance here? Use composition instead. Whatever Mob and Monster have in common → move it over to it’s own component and have Mob and Monster do their own specific thing without inheritance.

Also I suggest better naming for your classes, Enemies in Games can get very complicated over time, health, stun, various attacks, loot drop, physics, animations, (death) particles - you shouldn’t call any class just “Enemy” or in this case “Monster” or “Mob”, it should be called “MonsterMovement”, “MonsterDeath”, “MonsterLootDrop”, “Monster Attack”, “Monster Animation” and so on.

Thank you very much for your informations, but can you please provide an example.

What I understood is that I will have to create another class/struct for my SerializedFields like runSpeed in AgentLocomotion etc., but then how to efficiently pass it to the ILocomotion? Also my issue is that AgentLocomotion does not have all functions ChaseLocomotion has. In case of interfaces will I have to declare properties/functions twice or the new “ChaseLocomotion” would compose AgentLocomotion?

public class AgentLocomotion : ILocomotion
{
    [SerializeField, HideInInspector] protected Transform transform;
    [SerializeField, HideInInspector] protected Mob entity;
    [SerializeField, HideInInspector] protected NavMeshAgent agent;

    [SerializeField] protected float baseSpeed = 1, runSpeed = 2, sprintSpeed = 4;
    protected float bonusSpeed = 1;
    public bool canMove { get; protected set; } = true;

#if UNITY_EDITOR
    public virtual void Validate(Mob newEntity)
    { // called by OnValidate() of GameManager
        entity = newEntity;
        transform = entity.transform;
        agent = entity.Agent;
    }
#endif
   
    public virtual void InDestinationRange()
    {
        agent.isStopped = true;
    }

    public virtual void MoveTo(...) { ... }  // uses baseSpeed and runSpeed

    ...
}

I did put speed SerializeFields into AgentLocomotion because in terms of efficiency it is where they are directly accessed.
All in all, I am still unsure how to make Monster use ChaseLocomotion-logic and Mob use AgentLocomotion by interfaces, which can’t be serialized.

It would be huge work to distribute all kinds of entities like Mob, Monster etc. into interface with individual components, if this was what you implied. Partly this is already the case for Mob-class i.e. ISubject, IInteractable, IEquipable, ISkillable, IDamageable, ICrowdControlable etc. ISkillable expects Mob to have the attached SkillsController-MonoBehaviour as property.

The idea more so is to express these on components rather than the encapsulated classes themselves. Ergo:

public interface IAgentLocomotion
{
    public AgentLocomotion AgentLocomotion { get; }
}

public class SomeMonster : Monobehaviour, IAgentLocomotion
{
    [SerializeField]
    private AgentLocomotion _agentLocomotion = new();
  
    public AgentLocomotion AgentLocomotion => _agentLocomotion;
}

It will be overall more flexible than inheritance. The idea of ‘not having some properties’ expressed in derived class is completely against the purpose of inheritance (which is moreso to enable polymorphism) and object oriented programming, and will create more and more problems as time goes on.

Thank you too for you time.

If you have many more then just Monster and Mob this will become gigantic. I did experienced it before, where I inherited Stats for all types i.e. EntityStats, MobStats, NpcStats, MonsterStats, EliteStats, PlayerStats etc. and same for Controller, but then I came to the conclusion that actually they just differ by its entity type, so I united the 3 (Stats, Controller, Entity) for all types into Entity, just kept the bases and PlayerController and PlayerStats. I mean if you need another entity type you would have to add 3 classes and the auto-property that refered from Stats ↔ Entity ↔ Controller (= 6 auto-property per entity type with case and variable shadowing using new-operator), is just too much, increases memory usage and slows due to additional casts … But I havn’t found a way to solve this all by interfaces. Maybe you can give an raw example? What I already have is ILootable for Monster with a LootController (loot table and drops). Just wanted to avoid it this time because all Mobs need AgentLocomotion, so it is not optional and I will have to add this to all Mob Prefabs, which feels like extra work.

And yes I plan to rename i.e. Monster-class to MonsterController-class, but currently it is more about how to script this all taking limits of serialization, unity and c# into account.

I havn’t gotten much into customizing Inspector. How to solve this by SerializeReference? Will the custom inspector overwrite entityLocomotions = new AgentLocomotion[ ] { new AgentLocomotion() } into new AgentLocomotion[ ] { new ChaseLocomotion() } if it is a Monster? If this is the case it doesn’t feel like a clean solution, but it might work and prevent me from having to set it manually via editor.

It’s worth noting, if you don’t know already, that you can GetComponent<T>() for interfaces, and it will return a component that implements said interface type (as said interface type, too).

Piece meal-ing functionality with small components expressed via interfaces is a well understood technique that perfectly meshes well with Unity’s general architecture.

Monster or MonsterController is pretty much the same. MonsterMovement would be more specific for example.

I guess your script is about movement? It has an array of locomotion that contains… Sprites? And timings?

Without understanding what you are trying to do it’s pretty hard to suggest anything.

A screenshot/video with a short description/genre of the game plus an explanation of what you’re trying to do with those scripts would do wonders here.

This can be achieved using generics and the where clause with the new constraint:

using System;
using UnityEngine;

[Serializable]
public abstract class AgentLocomotion
{
    public const int CHASE_ID = 1;

    public abstract int id { get; }
}

[Serializable]
public sealed class ChaseLocomotion : AgentLocomotion
{
    public override int id => CHASE_ID;
}

public abstract class Mob<TAgentLocomotion> : MonoBehaviour where TAgentLocomotion : AgentLocomotion, new()
{
    protected readonly TAgentLocomotion[] entityLocomotions = new TAgentLocomotion[] { new TAgentLocomotion() };
    public int entityLocomotionID => entityLocomotions[0].id;
    public virtual AgentLocomotion entityLocomotion => entityLocomotions[0];
}

[SelectionBase]
public sealed class Monster : Mob<ChaseLocomotion>
{
    public ChaseLocomotion chaseLocomotion => entityLocomotions[0];
}

Yes more flexible, but less performant? I think where I am stuck now is how the best way to pass speed

The locomotion should have a default depending on entity type, also modifiable in code, like set different default or even have several and can be changed during runtime.

Just creating a simple medieval fantasy rpg. You are right about MonsterMovement, but for now this feels too specific I might come back to it if I have time and really need it, but thanks for this important advice. The Monster script composed everything, also how it is handled on death, on health change, how stats are calculated etc. but also derive from parents, so I don’t have to code twice or create additional class like you say. I understood now, that i need to make everything more modular.

I think mostly my speeds, canMove needs to be put out so i can pass it as argument, which I did want to avoid because of performance. Instead I did seperate AgentLocomotion and ChaseLocomotion now, but still unsure if this is the best approach.

public enum MovementMode : byte
{
    Idle = 0, Walk = 1, Run = 2, Sprint = 3, Patrol = 4, Auto = 5
}

[System.Serializable]
public class AgentLocomotion
{
    public delegate void MoveUntilDelegate();

    [SerializeField, HideInInspector] protected Transform transform;
    [SerializeField, HideInInspector] protected Mob entity;
    [SerializeField, HideInInspector] protected NavMeshAgent agent;

    [SerializeField] protected float baseSpeed = 1, runSpeed = 2, sprintSpeed = 4, rotationSpeed = 1, autoSpeed = 2;
    protected float bonusSpeed = 1; // modify current speed, i.e. updated by stats
    public bool canMove { get; protected set; } = true;
    public float modeSpeed { get; protected set; }
    public MovementMode _movementMode;
    public MovementMode movementMode { get { return _movementMode; }
        set {
            _movementMode = value;
            modeSpeed = baseSpeed * bonusSpeed * GetSpeed(); }
    } // ai mode or user requested by input

#if UNITY_EDITOR
    public virtual void Validate(Mob newEntity)
    {
        entity = newEntity;
        transform = entity.transform;
        agent = entity.Agent;
    }
#endif

    public float GetSpeed()
    {
        if (_movementMode == MovementMode.Auto) return autoSpeed;
        else if (_movementMode == MovementMode.Run) return runSpeed;
        else if (_movementMode == MovementMode.Patrol) return 1f;
        else if (_movementMode == MovementMode.Walk) return 1f;
        else if (_movementMode == MovementMode.Sprint) return sprintSpeed;
        else  return 0;
    }

    public void SetSpeed()
    { // i.e. called by AI
        agent.speed = modeSpeed;
    }

    public void SetBonusSpeed(float addSpeedQuote)
    { // increase by quote
        bonusSpeed = 1 + addSpeedQuote;
    }

    public virtual void BlockMovement(bool blocked)
    {
        canMove = !blocked;
        agent.isStopped = blocked;
    }

    public virtual void InRange()
    {
        agent.isStopped = true;
    }

    public virtual void NotInRange()
    {
        agent.isStopped = false;
    }

    public virtual bool IsReachable()
    {
        return agent.remainingDistance != Mathf.Infinity || agent.pathStatus != NavMeshPathStatus.PathInvalid || agent.pathStatus != NavMeshPathStatus.PathPartial;
    }

    IEnumerator MoveToCoroutine(float walkRange = 0f, float range = 0f)
    {
        bool pathReachable;
        while (pathReachable = IsReachable() || agent.remainingDistance > walkRange)
        {
            yield return new WaitForSeconds(1f);
        }

        movementMode = MovementMode.Walk;
        SetSpeed();

        while (pathReachable = IsReachable() || agent.remainingDistance > range || agent.pathStatus != NavMeshPathStatus.PathComplete)
        {
            yield return new WaitForSeconds(1f);
        }

        WithinRange(); // stop agent
    }

    IEnumerator MoveUntilCoroutine(Vector3 endPosition, float blinkDuration, System.Action onEnd = null)
    {
        float fixedStep = Time.fixedDeltaTime / blinkDuration;
        float currentTime = 0;
        while (currentTime < 1f)
        {
            currentTime += fixedStep; // goes from 0 to 1, incrementing by step each time
            transform.position = Vector3.Lerp(transform.position, endPosition, currentTime); // move transform closer to end position
            yield return new WaitForFixedUpdate();         // leave the routine and return here in the next frame
        }
        transform.position = endPosition;
        if (onEnd != null) onEnd();
    }

    public virtual void MoveTo(Vector3 position, float walkRange = 0f, float range = 0f)
    { // range to start walk instead run/sprint and range
        movementMode = MovementMode.Run;
        SetSpeed();
        agent.destination = position;
        NotWithinRange();
        entity.StartCoroutine(MoveToCoroutine(walkRange, range));
    }

    public virtual void MoveUntil(Vector3 endPosition, float blinkDuration, System.Action onEnd = null)
    {
        entity.StartCoroutine(MoveUntilCoroutine(endPosition, blinkDuration, onEnd));
    }
}


[System.Serializable]
public class ChaseLocomotion
{
    [SerializeField, HideInInspector] protected Mob entity;
    [SerializeField, HideInInspector] protected NavMeshAgent agent;
    [SerializeField, HideInInspector] protected AgentLocomotion entityLocomotion;

#if UNITY_EDITOR
    public virtual void Validate(Mob newEntity)
    {
        entity = newEntity;
        agent = entity.Agent;
        entityLocomotion = entity.entityLocomotion;
    }
#endif

    public virtual void ChaseTarget(Vector3 targetPosition)
    {
        entityLocomotion.movementMode = MovementMode.Auto;
        entityLocomotion.SetSpeed();
        agent.destination = targetPosition;
    }

    public virtual void ResetChaseTarget(Vector3 resetDestinationPosition)
    {
        agent.isStopped = true;
        agent.isStopped = false;
        agent.destination = resetDestinationPosition; // i.e. spawnPoint for AI
    }
}

Wow, thanks that is awesome didn’t know it is possible. This might be good for some other cases I have, but what could cause another issue that it is tied, so that Monster would only allow ChaseLocomotion and not classes of AgentLocomotion-family.

For now I will go with modularity optionally add ChaseLocomotion to a entity class if it needs and call its functions seperately. Actually I wanted to do this for things like different npc behaviour as cook, hunter or monster, so depending on the behaviour that is currently selected the npc behaves differently.

.

Ideally you’re not passing anything around: use ScriptableObjects to configure stuff.

If you do have code that shovels data into a newly-created entity, I like this pattern:

Factory Pattern in lieu of AddComponent (for timing and dependency correctness):

https://gist.github.com/kurtdekker/5dbd1d30890c3905adddf4e7ba2b8580

That keeps it all tidy.

Only one way to find out: attach the profiler. Also, how often are you making these objects? How important is it to shave off microseconds of time if you’re only making them at level load time?

DO NOT OPTIMIZE “JUST BECAUSE…” If you don’t have a problem, DO NOT OPTIMIZE!

If you DO have a problem, there is only ONE way to find out. Always start by using the profiler:

Window → Analysis → Profiler

Failure to use the profiler first means you’re just guessing, making a mess of your code for no good reason.

Not only that but performance on platform A will likely be completely different than platform B. Test on the platform(s) that you care about, and test to the extent that it is worth your effort, and no more.

https://discussions.unity.com/t/841163/2

Remember that optimized code is ALWAYS harder to work with and more brittle, making subsequent feature development difficult or impossible, or incurring massive technical debt on future development.

Don’t forget about the Frame Debugger either, available right near the Profiler in the menu system. Remember that you are gathering information at this stage. You cannot FIX until you FIND.

Notes on optimizing UnityEngine.UI setups:

https://discussions.unity.com/t/846847/2

At a minimum you want to clearly understand what performance issues you are having:

  • running too slowly?
  • loading too slowly?
  • using too much runtime memory?
  • final bundle too large?
  • too much network traffic?
  • something else?

If you are unable to engage the profiler, then your next solution is gross guessing changes, such as “reimport all textures as 32x32 tiny textures” or “replace some complex 3D objects with cubes/capsules” to try and figure out what is bogging you down.

Each experiment you do may give you intel about what is causing the performance issue that you identified. More importantly let you eliminate candidates for optimization. For instance if you swap out your biggest textures with 32x32 stamps and you STILL have a problem, you may be able to eliminate textures as an issue and move onto something else.

This sort of speculative optimization assumes you’re properly using source control so it takes one click to revert to the way your project was before if there is no improvement, while carefully making notes about what you have tried and more importantly what results it has had.

I do appreciate your help, but you misunderstood me. It was about runSpeed, sprintSpeed etc. they are in AgentLocomotion. Once ChaseLocomotion don’t inherit from AgentLocomotion it wasn’t able to directly access these serialized fields. But I solved this by just make AgentLocomotion allow to access speed by public get/set functions. These values were used inside Update() of Mobs/Monsters. I am sure it must make a performance difference if you always access direct class field or instead of through 1 or 2 classes, but for modularity I will sacrifice a bit depending how often it needs to be accessed. I do have realtime combat in my rpg, the locomotion and further stuff is used by AIBrain.

The issue I still have is something like npc behaviours i.e. combat logics, cooking, vendoring, guarding etc. I have to use ScriptableObjects? I like it when it has a default by class-type on initialization without extra calls (OnValidate, Awake…).

I agree with Kurt. These immutable values should honestly just be authored in scriptable objects.

Understand the preference for everything to be auto-initialised, but the bread and butter of Unity is referencing objects via the inspector.

Inheritance can be used several ways, most notably the way I use it requires no Abstract/Virtual/Override functions at all.

But I’m having trouble giving an example, since you seem set on making a separate “move” class(locomotion), which easily could just be a function in the parent class that handles children when they need it.

Again, this would be something in the parent class, that the child(npc) would use if it’s declared “jobType” were to specify this.

So in conclusion, many(a lot of) “move” functions are best handled by one Update(), instead of each class using it’s own Update()'s, as each call to a new Update() chews up performance(minor problem until mass index). So in this regard, a CharacterManager.cs class would be more appropriate for multiple transform repositioning.

And as far as jobs for the npc’s, you basically have “go here” and “do this at this position” as stated in the job type declaration of “work position”, “get resource position”, “go home, tired, day over” would all be generic methods populated by each individual npc on what they do, and where they do it.

Sorry if my answers are vague, I’m not quite fully sure on what it is you wish to have happen exactly.

But as you’ve noticed, there are many ways to accomplish the same goal, when it comes to coding. It really boils down to what you’re comfortable with using, and what makes more sense to you(it’s your game, and your code). :slight_smile:

You mean because virtual and override can limit you? On the other hand it reduces coding redundancy or you have to module it into extra class.

Not sure what you mean by “just be a function in the parent class”. This way even more is inside parent class and I lose modularity if I would want to use AgentLocomotion for other classes than parent one. Or you meant I should put the functions into i.e. MovementManager and call the functions with parameter (entity or agent)? Is it less optimized to pass additional object to function or to have AgentLocomotion attached to all classes that needs it and call without extra parameter? I mean you have to pass agent/entity always while it will never change for the corresponding entity.

I think I need to distinguish between the jobType and capabilities like entity is able to detectTarget (detectRange), inFieldOfView, huntTarget, protectSpawnInRadius. Maybe I need to split those like in Behaviour Tree Node?

You mean one Update for all entities (npcs, monsters, player) or per entity?

Can you populate / have initial set of “jobTypes” per class i.e. EliteMonster has EliteBuffTriggers, but no InnkeeperJobs and the Innkeeper vice versa?

If you’re not overriding/implementing anything from a base class, then you should ask yourself if you should be using inheritance at all.

There is the ‘subclass sandbox’ pattern approach, but honestly it’s a pretty old school approach that I feel is superseded by what Unity enables.

Inheritance is a means to and end for polymorphism.

In this situation OP direly needs a composition approach, and I think some form of pluggable data and behaviour with scriptable objects, possibly with [SerializeReference] as well.

I’m not sure if virtual can technically limit you, although there was a reason why I strayed away from it long ago, so maybe? But I just refer to there being different ways of using Inheritance, as the way I use it are different than examples I’ve seen.

There are 2 different ways I use it, depending on the structure of the project. In some cases, from the “master” class that houses all script-to-script communication, has all classes inherited, 2 sub-classes would be made from that, a “static object” and “non-static object” base class. Anything with movement/rotation inherits from “non-static” and same for still like objects inheriting from “static”. And of course multiple sub-classes from there, i.e(Characters.cs, Animals.cs, Projectiles.cs, etc…).

The other way I use in some cases, is the manager class only communicates with master, and can easily read the lists of instances through it and move them without having any inherited connection to moving entities, just their references.

Either way you boil it down, it’s about ease, less calls, and proper communication. Also about not having any limitations, as you will incur with scriptable objects or interfaces. Watch Code Monkey’s video on issues with scriptable objects, as I can’t remember the details, so it may(or may not) be a factor in your case, it’s just something I recall.

As I would do, would be having those functions within the parent class(however far up depending), and jobType to me would just be an enum, that once the state is set on the particular child class, it runs only the logic needed for that state. As most of my child classes are pretty empty, except for very specific things just for that particular class.

Yes, as stated, multiple classes with their own Update() methods, in high quantity will bog down performance. As this video can best explain:
Practical Optimizations

Easily, if it were something you wanted all sub-classes to have the possibility of using, then it’s function would just be within the proper parent class. With Inheritance everything is possible, this is why majority of classes inherit from “MonoBehaviour”. All I do is keep on inheriting, lol…

But I’m not trying to convince you to do things the way I’m doing them, all I’m trying to say is there are other ways to reach the same goal in the end. How you wish to organize, structure, and script communicate? Is purely up to you, it’s your code, and your game. :slight_smile:

With in conclusion, you “technically”(keyword technically) can make a game using 1 script. So all Inheritance, Scriptable Objects, Interfaces, and Modules do is just split that up. So it all depends on how you want to set it up, as some like individual classes for each little thing, and others prefer to group them lowering the amount of classes needed.

I personally like having a fair amount of scripts. :slight_smile:

I usually try to avoid using virtual methods, because it forces the programmer that is creating a derived class into the awkward position of having to decide at what point to execute the implementation in the base class.

Take these classes for an example:

public class Base
{
    private bool setupDone = false;

    public virtual void Setup()
    {
        SetupSomeStuff();
        setupDone = true;
    }
}

public class Derived : Base
{
    public override void Setup()
    {
        //base.Setup(); // ?

        SetupMoreStuff();

        //base.Setup(); // ?
    }
}

Should base.Setup be called at the very beginning of the method, so that all member variables in the base class will be initialized properly, and it’s safer to perform additional setting up on top of that without potential NullReferenceExceptions?

But then setupDone would get set to true before Setup has actually finished in the derived type, which would be misleading. So maybe it’s better to call base.Setup at the very end instead. You can always just test that nothing breaks in practice when doing it like this so it should be a pretty safe approach, right?

But wait… maybe base.Setup shouldn’t actually even be called at all in this case… the derived type already sets up all the same member variables, so calling base.Setup would just be wasted work, or worse yet, result in overwriting the already initialized variables with wrong values. Maybe setupDone should just be changed to protected so it can be set to true directly by the derived type :face_with_spiral_eyes::question:

Even if an XML documentation comment was added to the base class to tell the programmer how they should handle this conundrum, the programmer could easily just forget to call base.Setup, and the compiler wouldn’t warn about it at all.

And the worst part is that with this kind of setup, the base type and all derived types are very tightly coupled together. Making even a slight change to the Setup method in the base class could cause any derived types to break without warning.

I think this is the big trap where the use of inheritance can start becoming detrimental to the project, and why the composition over inheritance principle is such a big thing.

Abstract methods on the other hand don’t have the aforementioned problems.

As there’s no base implementation that needs to be called at any point, the derived method won’t get tightly coupled with the base class’s implementation details to that level.

And if the programmer forgets to implement the method, the compiler will warn them.

Same story with using inheritance to automate some behaviour in the base class, like keeping track of all active instances by adding them to a list. It can just work automatically when a programmer derives from the type, and doesn’t require the programmer to go and read the implementation details in the base class.

This is pretty easily solved:

public class Base
{
    private bool setupDone = false;

    public void Setup()
    {
        SetupSomeStuff();
        SetupInternal();
        setupDone = true;
    }
 
    protected virtual void SetupInternal() { }
}

public class Derived : Base
{
    protected override void SetupInternal()
    {
        SetupMoreStuff();
    }
}

I take this approach a lot to remove the burden having having to call base methods a lot. The virtual methods are more so ‘added extras’ I can hook into.

Though mind you I’m almost always using inheritance for the sake of composition.