Estados globais do teclado

7

Eu tenho a seguinte idéia sobre o processamento de entrada do teclado. Capturamos a entrada na classe "principal" do jogo, como esta:

protected override void Update(GameTime gameTime)
{
    this.CurrentKeyboardState = Keyboard.GetState();

    // main :Game class logic here

    base.Update(gameTime);

    this.PreviousKeyboardState = this.CurrentKeyboardState;
}

reutilize os estados do teclado (que têm internalescopo) em todos os outros componentes do jogo. As razões por trás disso são 1) minimizar a carga de processamento do teclado e 2) reduzir a "poluição" de todas as outras classes com variáveis ​​de estado do teclado semelhantes.

Como eu sou um noob no desenvolvimento de jogos e XNA, gostaria de saber se tudo isso parece razoável.

ATUALIZAÇÃO: Se alguém estiver interessado, a classe de utilidade real, como sugerido por David Gouveia , que criei pode ser encontrada aqui .

Petr Abdulin
fonte

Respostas:

12

Sim, é perfeitamente razoável, e eu poderia deixar por isso mesmo!

... mas pessoalmente eu prefiro ter um pouco mais de encapsulamento. Portanto, em vez de gerenciar o estado dentro da Gameclasse e fornecer acesso global a ele, prefiro agrupá-lo em sua própria classe.

Aqui está um exemplo da memória. Não tenho certeza se perdi alguns detalhes, mas o importante é a ideia geral:

public static class InputManager
{
    public static void Update()
    {
        _previousKeyboardState = _currentKeyboardState;
        _currentKeyboardState = Keyboard.GetState();
    }

    public static bool IsKeyDown(Keys key) 
    {
        return _currentKeyboardState.IsKeyDown(key);
    }

    public static bool IsKeyUp(Keys key)
    {
        return _currentKeyboardState.IsKeyUp(key);
    }

    public static bool OnKeyDown(Keys key)
    {
        return _currentKeyboardState.IsKeyDown(key) && _previousKeyboardState.IsKeyUp(key);
    }

    public static bool OnKeyUp(Keys key)
    {
        return _currentKeyboardState.IsKeyUp(key) && _previousKeyboardState.IsKeyDown(key);
    }

    private static KeyboardState _currentKeyboardState;
    private static KeyboardState _previousKeyboardState;
}

Então, na parte superior, Game.Updateeu simplesmente chamo Update no gerenciador:

InputManager.Update();

E, finalmente, em qualquer outro lugar do jogo, posso usar o wrapper diretamente:

if(InputManager.OnKeyDown(Keys.Space))
{
    // Shoot once
}

Algumas vantagens:

  • Como na sua solução, há apenas um lugar no aplicativo que precisa gerenciar os estados atuais e anteriores do teclado.
  • Mas, em vez de poluir a classe do jogo com o processamento do teclado, ele é encapsulado em sua própria classe apenas para isso.
  • A classe é estática, tornando-a acessível globalmente, de modo que, se você não quiser, não precisará fornecer acesso global à sua classe de jogo.
  • Também é facilmente reutilizável - se você iniciar um novo projeto, poderá simplesmente incluir essa turma e pronto.
David Gouveia
fonte
Enquanto você está nisso, torne a API fácil de gravar e reproduzir. Dessa forma, você pode usar entradas enlatadas para fins de teste posteriormente.
Patrick Hughes
@PatrickHughes, você poderia elaborar um pouco do seu comentário? Que tipo de abordagens posso adotar para isso? Alguns links podem ser úteis.
quer
2
@PetrAbdulin Você deseja manter uma lista de KeyboardStateobjetos associados aos registros de data e hora em uma estrutura. Como você jogar o seu jogo para o teste, pegue a gameTime.TotalGameTimecada quadro e colocá-lo em um struct com o _currentKeyboardStatee no jogo parar gravação que lista de KeyboardStates e TimeSpan.Milliseconds ints para o disco. Então, quando você executar o jogo em modo de teste de entrada, leia as KeyboardStates e inté a partir deste arquivo e lê-los a partir da verificação de lista que o próximo KeyboardState's timestamp associado corresponde ao atual gameTime.TotalGameTime.Millisecondspropriedade.
precisa saber é o seguinte
@ michael.bartnett muito obrigado pela explicação detalhada. Tudo isso faz sentido.
quer