De que se trata o artigo

Este artigo apresenta conceitos introdutórios da plataforma de desenvolvimento de Games da Microsoft – o XNA. Começa apresentando a estrutura básica dos programas desenvolvidos nesse framework e, avançando, apresenta algumas técnicas para animação 2D. Para concluir, ajuda a dar os primeiros passos no desenvolvimento de aplicações 3D.


Para que serve

XNA permite a criação de Games para PC, XBOX 360 e Windows Phone 7. O mercado de games é um dos que vem atingindo maior crescimento nos últimos anos. Entender como funciona o processo de desenvolvimento de um game, usando XNA, permite ao desenvolvedor considerar participar desse mercado. Além disso, XNA é uma das principais tecnologias de desenvolvimento para o Windows Phone 7.


Em que situação o tema é útil

Desenvolver competências para participar do desenvolvimento de um Game para PC, XBOX 360 ou Windows Phone 7. Entender o funcionamento e dinâmica dos games. Fazer um comparativo de performance entre PC, XBOX 360 e Windows Phone 7. Entender os fundamentos de animação 2D. Compreender a dinâmica e funcionamento de programas em 3D. Desenvolver habilidade na utilização de patterns de execução para programas de alta performance.

XNA

Neste artigo serão apresentados os conceitos fundamentais relacionados ao desenvolvimento de Games para PC, XBOX 360 e Windows Phone 7 utilizando XNA. Partindo disso, apresento a composição básica de um Game. Serão apresentados detalhes dos templates padrões, a Content Pipeline, a animação de Sprites 2D e, finalmente, animação 3D. De forma bastante prática, será demonstrado como XNA pode representar uma alternativa interessante para desenvolvimento de programas interativos, onde há necessidade de performance e compatibilidade entre muitas plataformas.

XNA é um framework para desenvolvimento de jogos, desenvolvido pela Microsoft, que, supostamente, torna a criação de jogos (para PC, Xbox 360 e Windows Phone 7) muito mais fácil (ou menos difícil).

XNA (sigla em inglês para XNA’s not Acronymed) é considerado por muitos como um substituto para o Managed DirectX. Ele pode ser baixado e utilizado gratuitamente. Sua primeira versão surgiu em 2006, a segunda versão em 2007, a terceira em outubro de 2008 e a quarta em setembro de 2010 (juntamente com o pacote de desenvolvimento para o Windows Phone 7.

Nesse artigo, será apresentado o XNA Game Studio 4.0, que é uma extensão do Visual Studio para desenvolvimento de games com XNA. Ele utiliza o XNA Framework 4.0. É suportado por todas as versões do Visual Studio 2010 com suporte a C# (Standard, inclusive) ou ainda pelo Visual C# 2010 Express Edition.

O XNA 4.0 permite que desenvolvamos games para Windows Vista, Windows 7, Xbox 360 e Windows Phone 7. Entretanto, para executar jogos feitos em XNA no Windows, a máquina deverá estar equipada com uma placa de vídeo que suporte WDDM 1.1 e DirectX 10 (ou posterior).

O XNA Game Studio 4.0 está disponível para download sem custos. Seu processo de instalação é fácil e intuitivo. Antes de avançar, certifique-se de que você possui uma versão adequada do Visual Studio e que seu hardware apresenta as características mínimas exigidas pelo framework.

Tendo instalado o XNA Game Studio 4.0, é possível iniciar o desenvolvimento da primeira aplicação XNA. A Figura 1 ilustra a criação de uma aplicação XNA utilizando o template Windows Game (4.0). Nessa figura podemos ver os demais tipos de templates disponibilizados para desenvolvimento com XNA.

Figura 1. Criando um projeto XNA

Após criar uma aplicação, sem fazer qualquer modificação, se o programa for executado tem-se uma tela preenchida com uma tonalidade de azul (Figura 2). A tela simples parece não ser algo muito animador, mas, acredite, esse é um grande passo se comparado ao que era necessário há alguns anos. Perceba que se seu computador não possuir recursos de vídeo suficientes, a aplicação indicará falha durante a carga.

Figura 2. Aplicação XNA

Entendendo a estrutura básica de um programa XNA

O template padrão carregado pelo Visual Studio carrega uma boa quantidade de código. Para entender como as coisas funcionam, comecemos pelo arquivo Program.cs (Listagem 1).

Listagem 1. Arquivo Program.cs


  using System;
   
  namespace Smurfs
  {
  #if WINDOWS || XBOX
      static class Program
      {
          static void Main(string[] args)
          {
              using (Game1 game = new Game1())
              {
                  game.Run();
              }
          }
      }
  #endif
  }

O código de inicialização é muito simples. Na prática, uma instância da classe Game1 é instanciada e tem seu método Run executado. As coisas ficam realmente um pouco mais interessantes na classe Game1 (Listagem 2).

Listagem 2. Arquivo Game1.cs


      1 using Microsoft.Xna.Framework;
      2 using Microsoft.Xna.Framework.Graphics;
      3 using Microsoft.Xna.Framework.Input;
      4 
      5 namespace FirstXnaApp
      6 {
      7     public class Game1 : Microsoft.Xna.Framework.Game
      8     {
      9         GraphicsDeviceManager graphics;
     10         SpriteBatch spriteBatch;
     11 
     12         public Game1()
     13         {
     14             graphics = new GraphicsDeviceManager(this);
     15             Content.RootDirectory = "Content";
     16         }
     17 
     18         protected override void Initialize()
     19         {
     20             base.Initialize();
     21         }
     22 
     23         protected override void LoadContent()
     24         {
     25             spriteBatch = new SpriteBatch(GraphicsDevice);
     26         }
     27 
     28         protected override void UnloadContent()
     29         {
     30         }
     31 
     32         protected override void Update(GameTime gameTime)
     33         {
     34             if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
     35                 this.Exit();
     36 
     37             base.Update(gameTime);
     38         }
     39 
     40         protected override void Draw(GameTime gameTime)
     41         {
     42             GraphicsDevice.Clear(Color.CornflowerBlue);
     43             base.Draw(gameTime);
     44         }
     45     }
     46 }

Neste código podemos perceber a presença de um construtor, dois atributos e cinco métodos. O significado desse código ficará mais claro nas próximas seções.

O objeto GraphicsDeviceManager

Como pode ser percebido em nossa listagem anterior, um objeto do tipo GameDeviceManager é instanciado logo na inicialização do Game. Este objeto é muito importante, pois ele provê ao desenvolvedor uma forma padrão de acessar os recursos gráficos de um PC, de um Xbox 360 ou do Windows Phone 7.

GraphicsDeviceManager possui uma propriedade chamada GraphicsDevice que representa o dispositivo gráfico disponível no computador. Toda comunicação entre um programa XNA e a placa de vídeo (ou melhor, a Unidade de Processamento Gráfico [GPU]) presente no dispositivo, ocorre através desse objeto.

O objeto SpriteBatch

O segundo atributo mantido pela classe Game1 é do tipo SpriteBatch. Trata-se do objeto que usaremos para desenhar Sprites. Um sprite é uma imagem 2D ou 3D que usamos para compor uma cena. As cenas de jogos 2D são compostas por múltiplos sprites.

A Figura 3 explica bem o conceito: cada jogador é um sprite, a imagem do background é um sprite, os placares são sprites, a mensagem “Fight!” é um sprite. Numa generalização grosseira, podemos assumir que um sprite em nossa cena como uma espécie de controle em um formulário.

Figura 3. Mortal Kombat (múltiplos sprites)

Carregando objetos do Game: Método Initialize e LoadContent

O método Initialize é o “lugar certo” para iniciar variáveis e outros objetos. A lógica de execução do tipo Microsoft.Xna.Framework.Game (de onde derivamos Game1) garante que o objeto GameDeviceManager já terá sido inicializado e poderá ser utilizado na inicialização de objetos que dependam de suas configurações.

O método LoadContent é chamado após a execução do método Initialize ou em qualquer momento onde seja aconselhável recarregar objetos gráficos do game (quando ocorrer mudanças nas configurações do dispositivo gráfico, por exemplo). Nesse método deverá ocorrer a carga de imagens, modelos 3D, sons, entre outros recursos.

The Game Loop

Logo que tenha sido concluída a carga do jogo, nos métodos Initialize e LoadContent, é iniciada uma rotina identificada como Game Loop. O conceito de Game Loop representa uma mudança substancial na forma como estamos habituados a pensar quando codificamos aplicações “normais”. Na prática, nosso código XNA nunca fica “esperando”.

Essencialmente, um Game Loop consiste de uma série de métodos que são chamados repetidamente até que o jogo encerre. No XNA, o game loop chama repetidamente apenas dois métodos: Update e Draw. Toda a lógica do game deverá ser acionada através desses métodos. Perceba:

  • O método Draw é usado para (surpresa!) “desenhar coisas”. Obviamente, você pode colocar código que faz outras coisas sendo executado a partir desse método, mas… não é legal;
  • O método Update é lugar para “processar o estado do game. Na prática, podemos dizer que todo processamento que não envolva desenho deve ser chamado a partir desse método. Onde acionar cálculo de atualização da posição de objetos? No método Update! Onde checar colisões? No método Update! Onde atualizar o placar? No método Update (desenhar o placar, é no Draw)! Verificar se o jogo foi concluído? No método Update.

Sem registro de eventos! Não insista!

Outro aspecto provavelmente novo para quem começa a desenvolver games é a inexistência de registro de eventos. Geralmente, aplicações desktop são programadas apenas para responder eventos do usuário. Por exemplo, se estiver escrevendo um formulário de cadastro, provavelmente fará o projeto da interface adicionando campos que precisam ser preenchidos, um botão para Salvar, outro para Descartar. Seu programa fará alguma coisa apenas quando um desses botões for pressionado, ou enquanto o usuário faz alguma digitação, ou na mudança de foco. De qualquer forma, seu programa apenas reage a eventos disparados por ações dos usuários.

Por outro lado, desenvolvimento de games é apenas “influenciado” pelos eventos do usuário. O programa “continua rodando” no lugar de ficar esperando que alguma coisa aconteça. Por exemplo, no lugar de esperar que o sistema “anuncie” que o usuário moveu o mouse, o jogo precisa “perguntar” para o sistema se o mouse foi movido. Importante: um jogo sempre está executando alguma ação, independente de qualquer entrada do usuário. Uma lógica mal implementada faz com que um jogo fique pouco responsivo. A “culpa” não é do dispositivo e sim do código malfeito. Examinando o código da Listagem 2 novamente, percebemos esse conceito claramente no método Update (Listagem 3). Este método faz com que o jogo seja encerrado quando o usuário pressionar o botão “back” no gamepad (controle).

Listagem 3. Método Update


     32         protected override void Update(GameTime gameTime)
     33         {
     34             if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
     35                 this.Exit();
     36 
     37             base.Update(gameTime);
     38         }

The Game State

Como mencionado antes, o método Update é onde devemos realizar qualquer alteração de estado do jogo. Aliás, Game State é um conceito extremamente importante; é a forma como o jogo “sabe” o que está acontecendo. Jogos tipicamente possuem “estados” significativamente diferentes, como:

• Mostrando um splash screen;

• Mostrando telas de placar;

• Mostrando seleção de jogadores;

• Durante a “ação”:

o Jogador em estado normal;

o Jogador com mais força;

o Jogador “finalizando” uma jogada (fatality do Mortal Kombat, lembra?)

• Mostrando indicadores de fim-de-partida.

Tipicamente, todas as modificações no “estado” do jogo ocorrem dentro do método Update e são “desenhados” no método Draw.

Finalizando o jogo: método UnloadContent

Com XNA, sempre que o game loop é interrompido, o método UnloadContent é chamado. Esse método é usado para “destruir” quaisquer conteúdos que tenham sido carregados, durante o método LoadContent, e precisem de algum tratamento especial. Tipicamente, XNA (assim como .NET) irá fazer a garbage collection. Entretanto, caso algum objeto que precise de tratamento especial tenha sido carregado, o método UnloadContent é o lugar onde essa descarga deverá ocorrer.

Representando graficamente o fluxo básico de um game em XNA

Para fixar bem o conceito, é apresentado um resumo gráfico do fluxo de execução de um jogo em XNA (Figura 4).

Figura 4. Fluxo básico XNA

Mais uma vez:

• A execução do game começa no método Initialize;

• O método LoadContent é executado em seguida e faz a carga do “conteúdo” que será utilizado durante o jogo (texturas, modelos 3D, sons);

...

Quer ler esse conteúdo completo? Tenha acesso completo