Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Advice requested for "command" design pattern

Discussion in 'Scripting' started by hamberge, Jul 25, 2019.

  1. hamberge

    hamberge

    Joined:
    Aug 30, 2015
    Posts:
    36
    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!
     
  2. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,745
    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).
     
  3. hamberge

    hamberge

    Joined:
    Aug 30, 2015
    Posts:
    36
    Thanks. Using scriptable objects for this makes a lot of sense.

    Here is a stab at something simple:

    Code (CSharp):
    1. public abstract class Command : ScriptableObject
    2. {
    3.   public string name;
    4.   public virtual void Execute();
    5. }
    6.  
    7. public class Command1 : Command
    8. {
    9.  public int param1;
    10.  public override void Execute()
    11.   {
    12.     DoSomething(param1);
    13.   }
    14. }
    15.  
    16. public class Command2: Command
    17. {
    18.   public GameObject param1;
    19.   public override void Execute()
    20.   {
    21.     DoSomethingElse(param1);
    22.   }
    23. }
    24.  
    25. public class CommandableBehaviour : MonoBehaviour
    26. {
    27.   public List<Command> commands;
    28.   public Panel commandButtonWindow;
    29.   public ButtonPrefab buttonPrefab;
    30.   void Awake()
    31.   {
    32.     foreach(Command c in commands)
    33.     {
    34.       Button currentButton = buttonPrefab.Instantiate(commandButtonWindow.transform);
    35.       currentButton.onClick.AddListener(c.Execute);
    36.       //set button text to c.name
    37.     }
    38.     //also disable this in awake... a separate select component will enable this.
    39.   }
    40. }
    41.  
    Then instantiate the Command1 and Command2, and set their parameters in the instance. Drag them to the public List<Command> 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?
     
    Last edited: Jul 25, 2019
  4. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,745
    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.
     
  5. hamberge

    hamberge

    Joined:
    Aug 30, 2015
    Posts:
    36
    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.
     
  6. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,745
    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.