Class derivation problem

I’m currently working on a 2D tower defense game. The enemies are spawned and units try kill them. Unit has an abstract base class BaseUnit, which currently has a lot of logic(all of it) and I don’t really like it. I’ve just separated all the upgrading logic to another class. Here are some simplified code examples.


BaseUnit cass:

public abstract class BaseUnit : MonoBehaviour
{
      protected UnitActiveStats activeStats;
      //other data


      protected abstract void Attack();
      //other functions
}

UnitArcher class:

public class UnitArcher : BaseUnit {
      
      protected void Attack(){
            //attack logic
      }
}

UnitUpgrading class with separated logic from BaseUnit:

[RequireComponent(typeof(BaseUnit))]
public class UnitUpgrading : MonoBehaviour {

    protected bool isBuilding; public bool IsBuilding => isBuilding;
    
    public void StartBuilding(UnitLevelID level)
    {
        //upgrade logic
    }
}

The problem is that in the UnitUpgrading class I want to access variables in the BaseUnit class and the only way around it I can think of right now is just having a referance to that script in the variable, something like this:

[RequireComponent(typeof(BaseUnit))]
public class UnitUpgrading : MonoBehaviour
{
    private BaseUnit unit;

    public void Initialize(BaseUnit unit)
    {
        this.unit = unit;
    }
}

Are there any better ways to do this?

Using inheritance for code reuse is almost always an anti pattern. It is for determining type relationships. It sounds like you are getting yourself into a bit of a mess probably because of a lack of understanding of better ways to structure code.


Use composition instead and I would suggest if you dont know what that means you should maybe learn some common design patterns. The gang of four book is the seminal book on OO design patterns but there are plenty of other great ones. One of which is explained here:



Another thing to note is not all your code has to be put into GameObjects. Only game objects need to be GameObjects almost all of your other code can just live in plain C# classes.


How about something like this

public interface IAttackable
{
   float Health { get; set; }
}

public interface ITowerBehaviour
{
    void Attack(IAttackable target);
}

public class ArcherBehaviour : ITowerBehaviour
{
    void Attack(IAttackable target)
    {
        // Some Attack implementation
        target.Health -= 20;
    }
}

 public class Enemy : MonoBehaviour, IAttackable
{
    public float Health { get; set; }
}

public class Tower : MonoBehaviour
{
    private ITowerBehaviour _behaviour { get; set; }

    private void Start() 
    {
        // Here you set your behaviour to a concrete implementation of ITowerBehaviour
        _behaviour = new ArcherBehaviour();
    }

    private void Update() 
    {   
         // Now when I call attack on _behaviour it will use the implementation in the Archer behaviour, which can be swapped out to any other implementation at runtime.
        if(Input.GetKeyDown(KeyCode.Space))
            _behaviour.Attack(someEnemy);     
    }
} 

You can mix and match patters, so you could use the decorator pattern on top of this strategy pattern for the upgrades system. Either way there are lots of better ways to do it than inheritance hopefully this inspires you to do some reading.