Overriding Start(), is this just bad code?

I’m currently trying to understand inheritance with regards to a base class that derives from MonoBehaviour.

This one’s kind of a two part-er. First, the Dictionary ‘actions’ that’s created in the base class only fires off the most recently added method despite the fact all options seem to be displaying just fine; it lists them all correctly in the game. I’m assuming that this is due to the way I’m setting up the inheritance with these objects.

So I’m starting to observe some undesired behavior from this design pattern and I suspect that this type of inheritance is just a bad solution to the whole system. Particularly:

  • It’s rather verbose when it comes to descendant Start() methods
  • My Dictionary<string, Action> is acting very strange.

I’ve declared:

  • GamePiece : MonoBehaviour
  • Structure : GamePiece
  • Generator : Structure

Currently I’m overriding GamePiece.Start() and calling base.Start() on every public override Start() for my each descendant.

So rather than directly ask a question about why the Dictionary isn’t working, I figured I’d start with the design itself. Is this just bad design and if so, is there a better way to approach inheriting from a MonoBehaviour?

GamePiece :

    public class GamePiece : MonoBehaviour {
        public Dictionary<string, Action> actions;
    	public virtual void Start () {
              actions = new Dictionary<string, Action>();
              actions.Add("Destroy", () => Destroy(this.gameObject));
    	}
}

Structure :

public class Structure : GamePiece {

    public override void Start() {
        base.Start();
    }
}

Generator:

public class Generator: Structure {

    Rigidbody2D rigid;
    bool isGeneratingPower;

    public override void Start () {
	base.Start ();
	actions.Add("Supply Power", () => SupplyPower());
        rigid = gameObject.GetComponent<Rigidbody2D>();
        rigid.angularVelocity = startSpeed;
    }
}

I had this same problem when developing the current game I’m working on. I found that a Component based approach to design works incredibly well in Unity, as GameObjects are already made up of a set of components and your scripts should follow this pattern as well.

A component based approach pretty much says that every object you have is the sum of its component parts. Splitting up functionality into different components makes your game incredibly modular and extendible.

So in your case, instead of having this multi-tiered inheritance you could have a component based design with some inheritance mixed in where appropriate.

Following this idea you could have the following.

public class GamePiece : MonoBehaviour {
  public Dictionary<string, Action> actions;
  public virtual void Start () {
    actions = new Dictionary<string, Action>();
    actions.Add("Destroy", () => Destroy(this.gameObject));
  }
}

Then your StructureComponent class can look like this.

[RequireComponent(GamePiece)]
public class StructureComponent : MonoBehavior {
  private GamePiece myGamePiece;

  void Start() {
    myGamePiece = getComponent<GamePiece>();
  }
}

Then it would make a lot more sense for any new structure to inherit from your StructureComponent class if need be. Also, the “RequireComponent” tag assures you that when you add the StructureComponent script to your game object, it will automatically add your GamePiece script as well.

You shouldn’t be adding to your base classes dictionary, that’s not good design in general. Instead you can make different components for your GamePieces that all have an action of their own.

public class GamePiece : MonoBehavior {
}

public class StructureComponent : MonoBehavior{
}

public class StructureWithActionComponent : StructureComponent {
  protected virtual void DoAction() { }
}

public class GeneratorComponent : StructureWithActionComponent{
  protected override void DoAction() { }
}

Hope this helps some. Although this example includes inheritance, the inheritance is reserved to components of the same general functionality. So more specific instances of a general component is ok for inheritance, as long as its function can be categorized as being the same as it’s base components function with some more specific functionality.