How to implement Command Pattern and Key Binding?

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

Upvotes: 1

Views: 1262

Answers (1)

David Arno
David Arno

Reputation: 43264

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]();

Upvotes: 2

Related Questions