XNA: Teclado e movimento

Olá, caros leitores, vamos continuar aqui nossa série sobre XNA. Como o título sugere, hoje veremos um pouco de como manipular o dispositivo de entrada padrão, o teclado, para executar ações em nossos games, como por exemplo o movimento dos personagens.

Recomendo que se você for acompanhar post a post, como um tutorial, salve o projeto para abri-lo e continuá-lo a cada novo post. Nesse segundo post, vou partir do que tínhamos ao final do primeiro. Nossa classe principal, Game1, estava assim:

public class Game1 : Microsoft.Xna.Framework.Game
{
    GraphicsDeviceManager graphics; 
    SpriteBatch spriteBatch;
    Texture2D avatar;

    public Game1()
    {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
    }

    protected override void Initialize()
    {
        base.Initialize();
    }

    protected override void LoadContent()
    {
        spriteBatch = new SpriteBatch(GraphicsDevice);
        avatar = Content.Load<Texture2D>("avatar");
    }

    protected override void UnloadContent()
    {
    }

    protected override void Update(GameTime gameTime)
    {
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            this.Exit(); 

        base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);

        spriteBatch.Begin();
        spriteBatch.Draw(avatar, new Vector2(300, 200), Color.White);
        spriteBatch.End();

        base.Draw(gameTime);
    }
}

Vamos dar um pouco de atenção a essa parte do código:

protected override void Update(GameTime gameTime)
{
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
        this.Exit(); 

    base.Update(gameTime);
}

Como eu havia comentado no primeiro post. Essas linhas têm o efeito de finalizar o jogo caso o jogador aperte backspace no seu teclado ou o botão Back do joystick do XBOX. Mas como estamos desenvolvendo para Windows, não é interessante obter a entrada do GamePad, e sim do teclado. No caso acima, existe uma “correspondência” entre o botão “Back” e a tecla backspace. Mas, por uma simples questão de quantidade, não haverá correspondentes no controle de XBOX suficientes para todas as teclas do teclado.

Assim, queremos controlar a entrada pelo teclado propriamente dito. Na verdade o processo é semelhante ao usado para o controle de XBOX. Em vez da classe estática GamePad, utilizaremos a também estática Keyboard, que oferece também um método GetState(), que retorna o estado do teclado em vez do estado do GamePad. Vamos apagar a parte do GamePad e atribuir o objeto KeyboardState, retornado pelo método GetState(), a uma variável para poder utilizá-lo várias vezes:

protected override void Update(GameTime gameTime)
{
    KeyboardState state = Keyboard.GetState();

    base.Update(gameTime);
}

Pronto, agora essa variável state nos dará acesso ao estado de todas as teclas do teclado, através dos métodos IsKeyDown e IsKeyUp, que recebem como parâmetro um item da enumeração Keys, representando alguma tecla, e retornam true ou false dependendo do estado da tecla.
Por exemplo, se quiséssemos executar uma ação quando a tecla space estivesse apertada, usaríamos o seguinte código:

protected override void Update(GameTime gameTime)
{
    KeyboardState state = Keyboard.GetState();

    if (state.IsKeyDown(Keys.Space))
    {
        // ações aqui!
    }

    base.Update(gameTime);
}

Visto isso, que tal tornar um pouco mais dinâmico nosso jogo? Seria interessante, por exemplo, movimentar o nosso avatar utilizando as teclas direcionais. Primeiramente, observemos o seguinte:

protected override void Draw(GameTime gameTime)
{
    GraphicsDevice.Clear(Color.CornflowerBlue);

    spriteBatch.Begin();
    spriteBatch.Draw(avatar, new Vector2(300, 200), Color.White);
    spriteBatch.End();

    base.Draw(gameTime);
}

O posicionamento de nossa imagem é determinado pelo objeto Vector2 enviado ao método Draw de spriteBatch. Ou seja, para movimentarmos a imagem, esse posicionamento tem que ser modificado em tempo de execução. Portanto, obviamente não podemos enviar valores constantes para o construtor do Vector2. Poderíamos usar variáveis numéricas que modificaríamos conforme ações no teclado, ou melhor ainda, utilizar uma variável do tipo Vector2, da qual modificaríamos os atributos X e Y.
Façamos assim:

public class Game1 : Game
{
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;
    Texture2D avatar;
    Vector2 posicao;
    . . .

Agora, ao desenhar a imagem do avatar, enviaremos esse Vector2 chamado “posicao” como parâmetro. Dessa forma, poderemos mudar suas coordenadas X e Y para “movimentar” a imagem. Como havíamos proposto, vamos fazer isso usando o teclado. Voltando ao método Update:

protected override void Update(GameTime gameTime)
{
    KeyboardState state = Keyboard.GetState();

    if (state.IsKeyDown(Keys.Up))
    {
        posicao.Y -= 5;
    }
    if (state.IsKeyDown(Keys.Down))
    {
        posicao.Y += 5;
    }
    if (state.IsKeyDown(Keys.Left))
    {
        posicao.X -= 5;
    }
    if (state.IsKeyDown(Keys.Right))
    {
        posicao.X += 5;
    }

    base.Update(gameTime);
}

Mas ainda é preciso fazer uma pequena mudança no método Draw, que é enviar o Vector2 posicao como parâmetro:

protected override void Draw(GameTime gameTime)
{
    GraphicsDevice.Clear(Color.CornflowerBlue);

    spriteBatch.Begin();
    spriteBatch.Draw(avatar, posicao, Color.White);
    spriteBatch.End();

    base.Draw(gameTime);
}

Experimente executar o jogo agora. Sim, a imagem se movimenta com as teclas direcionais! Está se movendo muito rápido? Basta mudar o valor que é acrescentado ou subtraído de posicao.X e posicao.Y. E por que agora a imagem começa no canto da tela? Porque nosso querido Vector2 posicao não foi inicializado, e portanto seus atributos X e Y terão o valor padrão de float, que é zero. Os “eixos” x e y têm sua origem no canto superior esquerdo da tela, que é onde nossa imagem ficará inicialmente posicionada, portanto.

Visto isso, amigo, você já é capaz de fazer coisas mais divertidas e diferentes ações para as inúmeras teclas do teclado. Mas o jogo ainda não está muito visualmente atraente, não é? Bom, esse incoveniente eu te ajudarei a resolver no próximo post, que focará o método Draw. Até lá!

3 comentários sobre “XNA: Teclado e movimento

  1. Lucas MartinsLucas disse:

    olha só, sei que é massante manter um blog, já tive um e eu mesmo me cansei, mas o conteúdo deste é ótimo, um material tão detalhado e simples assim sobre xna é raro de se ver, e olha que já li muita coisa gringa sobre o assunto
    parabéns e continuem os posts e o bom trabalho

    • Eric Yuzo disse:

      Valeu pelos comentários! É muito importante este feedback pra sabermos se nosso “trabalho” aqui no blog está sendo bem feito.
      Em relação aos posts sobre XNA, tenho certeza que, assim que o Victor se aliviar um pouco do trabalho + faculdade, ele vai continuar com seus posts.

Deixe um comentário