2013-10-29 1 views
1

저는 .NET으로 비디오 게임을 개발하고 있습니다. 그러나 명령 대기열을 올바르게 구현 한 다음 즉시 실행하는 방법에 대해 고심하고 있습니다.명령 패턴 및 키 바인딩을 구현하는 방법은 무엇입니까?

내 비디오 게임은 간단합니다. 움직이는 항공기입니다. 어떻게 제대로 명령 패턴을 구현할 수

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

을 그들이 때 제대로 모든 매개 변수가이 명령을 인스턴스화 : 명령 패턴의 내 구현은 내가 Player 클래스에이 명령의 관리를 구현, 다음과 같다 필수?

답변

2

여기서 핵심은 명령 패턴을 제시하는 "표준"방법은 가이드 라인이 아닌 규칙입니다 실현하는 것입니다 감사합니다. C#에는 위임자와 람다가 내장되어있어 ICommand 등을 정의 할 필요가 없습니다. 명령 클래스를 제거하면 플레이어 클래스를 크게 단순화 할 수 있습니다. 다음은 지금까지 전체에서이지만, 다행스럽게도 필자가 무엇을 의미하는지 보여줍니다

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); 
    } 

    ... 
} 

주요 변경 사항은 클래스로 MoveAircraft 방법을 이동 한 후 _actionBinding 사전에 폐쇄 람다를 통해 호출 할 수 있습니다. Dictionary<ActionMove,Action>은 ActionMove를 키로 사용하고 값없이 매개 변수가없는 void 메서드를 사용하여 사전을 정의합니다. 그런 다음 예 : () => MoveAircraft(_playerSpeed, 0f, _aircraft) 표현식은 _playerSpeed_aircraft의 현재 값을 MoveAircraft으로 전달하는 매개 변수없이 익명 void 메서드를 지정합니다.

이 방법을 호출하려면 다음과 같이하십시오. _actionBinding[ActionMove.MoveRight]();

+0

답장을 보내 주셔서 감사합니다. 그러나 앞으로 더 많은 명령을 추가하려면 어떻게해야합니까? Player 클래스가 너무 크고 다른 구성 요소와 결합되어 있을까요? –

+0

@ DavidJiménezMartínez 가장 간단한 해결책은 생성자를 통해 플레이어 클래스에 사전 인스턴스를 제공하는 것입니다. 그렇게하면 명령과 바인딩을 다른 곳에 설치할 수 있으며 플레이어 클래스를 결합 할 필요가 없습니다. 그러면 조롱 된 명령을 제공 할 수있을 때 단위 테스트가 더 쉬워집니다. –

+0

@ DavidJiménezMartínez 그렇다면, 클로저 동작의 이점 (즉, 항공기의 현재 가치와 명령에 대한 플레이어 위치의 전달)을 잃어 버리면 공공 게터를 통해 액세스 할 수있게됩니다. –

관련 문제