Advice requested for "command" design pattern

Hi all. I’m trying to design a “command” system for a top-down strategy game with buildings. To do this, I created a “HasCommand” component, which will connect UI buttons to functions whose identity can be set in the inspector. The functions are in another “Commands” component to be placed on the same gameobject. Because different buildings can obviously have different commands, I want to have the “Commands” component be completely different scripts for the different buildings. The commonality is that they would all implement a marker interface that does not require any methods be implemented. This would allow the HasCommand component to be agnostic to which Commands component you actually use.

In sum, each building game object would have a “HasCommand” component that links an inspector-settable function from a “Commands” component to an inspector-settable UI button. All inspector-settable functions must be in a “commands” component, however.

My question is: is this a good idea or a bad idea? If not a good idea, what is a better alternative?

Thank you!

I think youre overengeeniring this. Command is basic pattern. Command class should have only properties for parameters and command execution function. Make your commands completely independent scriptable objects. Create a CommandableBehaviour to hold list of commands. When object with such behaviour is selected, show commands in UI and if ordered, execute that command on that selected object(s).

Thanks. Using scriptable objects for this makes a lot of sense.

Here is a stab at something simple:

public abstract class Command : ScriptableObject
{
  public string name;
  public virtual void Execute();
}

public class Command1 : Command
{
 public int param1;
 public override void Execute()
  {
    DoSomething(param1);
  }
}

public class Command2: Command
{
  public GameObject param1;
  public override void Execute()
  {
    DoSomethingElse(param1);
  }
}

public class CommandableBehaviour : MonoBehaviour
{
  public List<Command> commands;
  public Panel commandButtonWindow;
  public ButtonPrefab buttonPrefab;
  void Awake()
  {
    foreach(Command c in commands)
    {
      Button currentButton = buttonPrefab.Instantiate(commandButtonWindow.transform);
      currentButton.onClick.AddListener(c.Execute);
      //set button text to c.name
    }
    //also disable this in awake... a separate select component will enable this.
  }
}

Then instantiate the Command1 and Command2, and set their parameters in the instance. Drag them to the public List variable in CommandableBehavior, which you place on a gameobject. Maybe do the button creation on demand instead of on Awake so you don’t have a bunch of inactive UI elements.

What do you think?

Panel and button should not be in the CommandableBehaviour because this way youre mixing commander and his army in one class. Panel and button may exist and may not, but this behaviour still commandable. Inverse your design. Make panel reference commandable and hold the button. This way you separate ui and character design. so they will not interfere each with other. UI designer only need to know there’s something commandable so he can create panels and buttons to send commands to it.

I see, so you’re saying the script that holds which commands are available should be different than whatever entity creates the buttons. That makes sense.

Yes. That’s because you may have multiple sources of commands for any commandable object and it won’t neccesary be ui panel. In other words, in this pattern we have 3 separate responsibilities. The command responsible for itself execution, commander is responsible for issuing commands and commandable provides data context for command to work on. According to OOP desing principles, responsibilities must be separated.