1

I'm developing a videogame with .NET, yet I'm struggling on how to properly implement a queueing of commands and then execute them at once.

My videogame is simple, it's an aircraft that moves. My implementation of the Command Pattern is the following, then I implement the management of these commands on the Player class:

public abstract class ICommand {
        Category CategoryProperty { get; set; }

        public abstract void Execute();
    }

public class MoveAircraftCommand : ICommand
    {
        private Vector2f _velocity;
        Aircraft aircraft;

        public Category CategoryProperty {
            get {
                return Category.PlayerAircraft;
            }
        }

        public MoveAircraftCommand (float vx, float vy, Aircraft v_aircraft) {
            _velocity = new Vector2f(vx, vy);
            aircraft = v_aircraft;
        }

        public override void Execute()
        {
            aircraft.Accelerate(_velocity);
        }
    }

//Then, There is the Player class that binds keys to actions, and actions to Commands.

public class Player
    {
public enum ActionMove {
            MoveLeft,
            MoveRight,
            MoveUp,
            MoveDown,
            ActionCount
        }

private IDictionary<Keyboard.Key, ActionMove> _keyBinding;
private IDictionary<ActionMove,ICommand> _actionBinding;

public Player()
        {
            _keyBinding = new Dictionary<Keyboard.Key, ActionMove>();
            _keyBinding.Add(Keyboard.Key.Left,ActionMove.MoveLeft);
            _keyBinding.Add(Keyboard.Key.Right,ActionMove.MoveRight);
            _keyBinding.Add(Keyboard.Key.Up,ActionMove.MoveUp);
            _keyBinding.Add(Keyboard.Key.Down,ActionMove.MoveDown);

/** Dunno how to bind the actions to commands without instantiating the command, Hard-Coding the parameters at start. Also Yet I don't have instantiated the aircraft object**/
float playerSpeed = 200f;
            _actionBinding.Add(ActionMove.MoveRight,new MoveAircraftCommand(+playerSpeed,0f,aircraft));
            _actionBinding.Add(ActionMove.MoveUp,new MoveAircraftCommand(0f,-playerSpeed, aircraft));
            _actionBinding.Add(ActionMove.MoveDown,new MoveAircraftCommand(0f,+playerSpeed,aircraft));
/** **/

/**This function pushes the Commands to a queue, in order to process them in order at once**/
public void HandleRealTimeInput(CommandQueue commands) {
            foreach (KeyValuePair<Keyboard.Key,ActionMove> entry in _keyBinding) {
                if (Keyboard.IsKeyPressed(entry.Key) && isRealTimeAction(entry.Value)) {
                    commands.Push(_factory.GetCommand(_keyBinding[entry.Key]));
                }
            }
        }

How can I implement properly the Command Pattern and instantiate these commands with all their parameters properly when they are required?

Thank you

1 Answer 1

2

The key here is to realise that the "standard" way of presenting the Command pattern is a guideline, not a rule. C# has delegates and lambdas built-in, so there is no need to define ICommand etc. By getting rid of the command class, you can greatly simplify your Player class. The following is far from complete, but it hopefully shows what I means:

public class Player
{
    private Aircraft _aircraft;
    private float _playerSpeed = 200f;

    private readonly IDictionary<Keyboard.Key, ActionMove> _keyBinding =
        new Dictionary<Keyboard.Key, ActionMove>
        {
            { Keyboard.Key.Left,ActionMove.MoveLeft },
            { Keyboard.Key.Right,ActionMove.MoveRight },
            { Keyboard.Key.Up,ActionMove.MoveUp },
            { Keyboard.Key.Down,ActionMove.MoveDown }
        };

    private readonly IDictionary<ActionMove,ICommand> _actionBinding =
        new Dictionary<ActionMove,Action>
        {
            { ActionMove.MoveRight, () => MoveAircraft(_playerSpeed, 0f, _aircraft) },
            { ActionMove.MoveUp, () => MoveAircraft(0f, -_playerSpeed, _aircraft) },
            ...
        };

    public MoveAircraft(float vx, float vy, Aircraft v_aircraft) 
    {
        var velocity = new Vector2f(vx, vy);
        aircraft.Accelerate(_velocity);
    }

    ...
}

The key changes are to move the MoveAircraft method into the class and to then invoke it via closure lambdas in the _actionBinding dictionary. The Dictionary<ActionMove,Action> defines a dictionary with ActionMove as the key and a void method with no parameters as the value. Then the eg () => MoveAircraft(_playerSpeed, 0f, _aircraft) expression specifies an anonymous void method with no parameters which passes the current value of _playerSpeed and _aircraft to MoveAircraft.

To call these methods, you'd simply do eg _actionBinding[ActionMove.MoveRight]();

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you for your answer. However, what if I wish to add more Commands in the future? Would it make the Player class too big and coupled with other components?
@DavidJiménezMartínez The simplest solution there is to supply the player class with an instance of Dictionary<ActionMove,ICommand> via its constructor. That way, the commands and binding can be set up elsewhere and the player class doesn't need to be coupled to them. That will also make unit testing easier as you can supply mocked commands.
@DavidJiménezMartínez Having said that, you'd then lose the benefit of the closure behaviour (ie the passing of the current value of aircraft and player position to the commands. They would therefore eg could become accessible via public getters.
All right, I'll try to assimilate your answer and test it at home with delegates. Thank you very much :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.