Aula 4 – Tratamento de Input
O objetivo desta aula é apresentar aos alunos os conceitos
básicos sobre como tratar a entrada de dados de diversos
dispositivos de input (com destaque para gamepad, mouse e
teclado) e tratamento básico de colisões 2D
Para superar algumas limitações do tratamento de input no
XNA, são usadas as classes de apoio (código aberto de uso
livre) criadas por Benjamin Nitschke,
http://benjaminnitschke.com
Há diversos exemplos práticos para esta aula, cada exemplo é
marcado por um slide escrito “demo”
Ao fim da aula é reservado um tempo para os alunos
exercitarem os conceitos apresentados, assim, não é
recomendável que os alunos realizem os demos juntos com o
professor, pois isso acaba tomando muito tempo da aula
1
XNA Game Studio
Aula 4
Tratamento de Input
Esteban Walter Gonzalez Clua
Agenda: Aula 4
Revisão
Arquitetura de um programa XNA
Tratamento de input do usuário
Uso de classes de apoio para tratamento de input
3
Revisão: Componentes do XNA Game Studio
Framework
4
Revisão: XNA Framework
Jogos
Framework
(extensões)
Starter Kits
Modelo de Aplicação
Framework
Graphics
(núcleo)
Plataforma
Legenda
Código
Direct3D
XNA já provê
Audio
Input
XACT
Você cria
Conteúdo
Componentes
Pipeline de Conteúdo
(content pipeline)
Math
XINPUT
Storage
Network
XCONTENT
Comunidade
5
Tratamento de input do usuário
6
Input no XNA Framework
O XNA Torna a obtenção do input do usuário
extremamente fácil
Suporte a
Xbox 360 gamepad, guitarra, tambores, volantes, pedais,
etc!
Keyboard
Mouse (apenas para Windows)
Modelo de programação imediato
Não demanda inicialização
Não demanda gerenciamento de estado
Tira uma fotografia do estado de todos os botões naquele
momento
7
Tipos de controle gerenciados
Enumeração gamePadType permite verificar o
tipo de controle, e método GetCapabilities
permite receber detalhes sobre capacidades.
ArcadeStickController - arcade stick.
DancePadController - dance pad.
DrumKitController - drum kit (tambor).
FlightStickController - flight stick (manche).
GamePadController - Xbox 360 Controller.
GuitarController - guitarra!
UnknownController - unknown type (futuros
dispositivos)
WheelController – wheel (volante).
8
Input no XNA Framework
Exemplo de desenvolvimento
multi-plataforma: Xbox 360 controller
Wireless ou wired (USB)
Pode ser usado tanto em jogos Windows como Xbox 360
A interface de programação é a mesma
Pode ser usado como controle PC tradicional!
wireless
receiver p/ PC
9
Input no XNA Framework
Xbox 360 controller
11 botões
2 triggers (alavancas)
2 direcionais analógicos
1 direcional digital
Dois motores de vibração
GamePadState state = GamePad.GetState(PlayerIndex.One);
10
Input no XNA Framework
Botões A, B, X e Y
Cada um pode estar
ButtonState.Pressed ou
ButtonState.Released
11
Input no XNA Framework
Botões Start e Back
Cada um pode estar
ButtonState.Pressed ou
ButtonState.Released
12
Input no XNA Framework
Botão Xbox Guide
Não é usado durante os
jogos
No PC...
Abre janela de configuração
do joystick
No Xbox 360...
Abre a dashboard
13
Input no XNA Framework
Direcionais thumb sticks
Valores contínuos
-1.0 a +1.0 no eixo X
-1.0 a +1.0 no eixo Y
Eixo Y incrementa de baixo
para cima
Contrário das coordenadas
da tela!
Podem ser pressionados
também, como um botão
ButtonState.Pressed ou
ButtonState.Released
14
Input no XNA Framework
D-pad
Quatro direções
Up
Down
Left
Right
Cada direção pode estar
ButtonState.Pressed ou
ButtonState.Released
Valores binários, não contínuos
É possível ter mais de uma
direção pressionada
Ex.: diagonais (Up + Left)
15
Input no XNA Framework
Triggers
Valores contínuos
0.0 a +1.0
16
Input no XNA Framework
Bumpers ou Shoulders
Cada um pode estar
ButtonState.Pressed ou
ButtonState.Released
Valores contínuos
17
Input no XNA Framework
Motores de vibração
Esquerda: baixa-freqüência
Direita: alta-freqüência
Cada um pode vibrar com
intensidade de 0.0 a 1.0
Valores contínuos (float)
1.0 é a vibração máxima
0.0 encerra a vibração – se não
atribuir 0, continua vibrando!
GamePad.SetVibration(PlayerIndex.One, 0.5f, 1.0f);
18
Tratamento de input do usuário
Vamos adaptar um dos demos anteriores
para incluir um novo objeto, controlado pelo
usuário via teclado, gamePad e mouse,
através dos seguintes passos:
1. Copiar a classe clsSprite e renomeá-la para
clsPlayer
2. Alterar o método Update para tratar o input do
usuário
3. Alterar os métodos do objeto principal (game1)
para incluir o novo componente e desenhá-lo
19
Tratamento de input do usuário
1. Copiar a classe clsSprite para clsPlayer
Dica: use Copy e Paste direto na janela de
“Solution Explorer” do C# Express
Após renomear, vamos incluir na classe clsPlayer:
using Microsoft.Xna.Framework.Input;
20
Tratamento de input do usuário
2. Alterar o método Update para tratar o input do
usuário - GamePad
public override void Update(GameTime gameTime)
{
Vector2 novaPosicao = posicao;
bool podeMover = true; // usado para teste das bordas da janela
// Muda a posição usando o thumbstick da esquerda
GamePadState gamePad = GamePad.GetState(PlayerIndex.One);
novaPosicao.X += gamePad.ThumbSticks.Left.X;
novaPosicao.Y -= gamePad.ThumbSticks.Left.Y;
// Atualiza a posição
if(podeMover)
posicao = novaPosicao;
}
21
Tratamento de input do usuário
2. Alterar o método Update para tratar o input do
usuário - Teclado
public override void Update(GameTime gameTime)
{
...
// muda a posição usando o teclado
KeyboardState keyboardState = Keyboard.GetState();
if (keyboardState.IsKeyDown(Keys.Up))
novaPosicao.Y -= 1;
if (keyboardState.IsKeyDown(Keys.Down))
novaPosicao.Y += 1;
if (keyboardState.IsKeyDown(Keys.Left))
novaPosicao.X -= 1;
if (keyboardState.IsKeyDown(Keys.Right))
novaPosicao.X += 1;
...
}
22
Tratamento de input do usuário
2. Alterar o método Update para tratar o
input do usuário – Mouse
public override void Update(GameTime gameTime)
{
...
// muda a posição usando o mouse
MouseState mouse = Mouse.GetState();
novaPosicao.X = mouse.X;
novaPosicao.Y = mouse.Y;
...
}
23
Tratamento de input do usuário
2. Alterar o método Update para tratar o input do usuário
– Testando as bordas da janela
public override void Update(GameTime gameTime)
{
Vector2 novaPosicao = posicao;
bool podeMover = true;
...
// testa a nova posição para não sair pelas bordas da tela
if(novaPosicao.X + textura.Width > this.Game.Window.ClientBounds.Width)
podeMover = false; // direita
if (novaPosicao.Y + textura.Height > this.Game.Window.ClientBounds.Height)
podeMover = false; // de baixo
if (novaPosicao.X < 0)
podeMover = false; // esquerda
if (novaPosicao.Y < 0)
podeMover = false; // de cima
// Atualiza a posição
if(podeMover)
posicao = novaPosicao;
}
24
Tratamento de input do usuário
3. Adicionar o objeto Player ao Game
private clsPlayer jogador;
...
protected override void LoadContent()
{
...
// carrega o jogador
jogador = new clsPlayer(this,
content.Load<Texture2D>(“player_xna_thumbnail"),
new Vector2(300, 100));
this.Components.Add(jogador );
}
25
Tratamento de input do usuário
...e finalmente atualizar o método Draw da classe Game
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
Desenho2D.Draw(spriteBatch);
jogador.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
Veja que as duas sprites são desenhadas com o mesmo
spritebatch, melhorando a performance!
26
Tratamento de input do usuário
Toque final: Incluindo detecção de colisão
1. Incluir código na classe Player que testa colisão
com objetos Sprite
2. Chamar código na classe principal (game1)
Incluir vibração no GamePad
27
Detecção de colisão
Algoritmo de “bounding box” é um dos mais
simples e comuns para detecção de colisão
A idéia é testar de uma “caixa” que contém a
sprite colide com a “caixa” da outra sprite
Melhorias no algoritmo podem considerar
diversas “caixas “ por sprite
28
Tratamento de input do usuário
1. Incluir código na classe Player que testa colisão com objetos
Sprite
public bool Colidiu(clsSprite sprite)
{
// Verifica se colidiu com a sprite
if (this.posicao.X + this.textura.Width > sprite.posicao.X &&
this.posicao.X < sprite.posicao.X + sprite.textura.Width &&
this.posicao.Y + this.textura.Height > sprite.posicao.Y &&
this.posicao.Y < sprite.posicao.Y + sprite.textura.Height)
return true;
else
return false;
}
29
Tratamento de input do usuário
2. Chamar código na classe principal (game1)
protected override void Update(GameTime gameTime)
{
...
// Testa se houve colisão
if (jogador.Colidiu(Desenho2D))
{
Desenho2D.velocidade *= -1;
GamePad.SetVibration(PlayerIndex.One, 1.0f, 1.0f);
}
else
GamePad.SetVibration(PlayerIndex.One, 0f, 0f);
...
}
30
Tratamento de input e detecção de colisão
Projeto: XNA 3.0 Demo - Input e colisão
31
Input não tem “memória”
Os objetos de input (Mouse, Keyboard,
GamePad) tiram uma “foto” do estado atual!
Não dá para saber se o mouse “está se movendo”,
só sua posição
Não dá para saber se o usuário acabou de apertar
uma tecla, ou se ela já estava apertada.
Não dá para saber a última direção em que o
usuário moveu o Mouse ou gamePad
=> Uso de classes de apoio (“helpers”)
32
Apoio ao tratamento de input
Classes de uso livre, criadas por Benjamin Nitschke,
http://benjaminnitschke.com
Input.cs
Mouse: Movimento, arraste, MouseInBox (se está
em determinada região), etc; e desabilitação das
rotinas de mouse quando rodando no Xbox 360
Teclado: Verificação de tecla “recém-pressionada”,
se é tecla especial, conversão de caracteres para
teclas
Gamepad: verificação de controles “recémpressionados”
33
Apoio ao tratamento de input
Uso das classes de apoio:
1. Incluir Input.cs (modificada) no projeto
2. Chamar Input.Update no update do jogo
Input.Update(gameTime);
3. Usar os métodos (exemplos)
if (Input.KeyboardUpJustPressed)
incremento = -1;
...
if(Input.GamePadLeftShoulderJustPressed)
incremento = -1;
...
if (Input.MouseLeftButtonJustPressed)
{
if (Input.MouseInBox(this[BotaoAtivo].retangulo))
this[BotaoAtivo].Executa();
}
34
Desafio 1: Navegação entre telas
Criar uma lista de telas
Navegar pela lista de telas
35
Criando uma classe “Tela”
A tela é fácil – mais simples que uma sprite!
class Tela
{
private Texture2D fundo;
//
Textura da tela
public Tela(Texture2D Textura)
{
fundo = Textura;
}
public void Draw(SpriteBatch Renderizador2D)
{
Renderizador2D.Draw(fundo, Vector2.Zero, Color.White);
}
public void Unload()
{
fundo.Dispose();
}
}
36
Navegando entre telas
Também é fácil – basta desenhar uma tela em vez da outra!
private Tela tela1;
private Tela tela2; private Tela telaAtual;
...
protected override void Initialize()...
Tela1 = new Tela(Content.Load<Texture2D>("Tela_Inicial"));
Tela2 = new Tela(Content.Load<Texture2D>("Tela_GameOver"));
telaAtual = Tela1;
...
protected override void Update(GameTime gameTime)...
if
(GamePad.GetState(PlayerIndex.One).Buttons.A==ButtonState.Pressed)
telaAtual = Tela2;
...
protected override void Draw(GameTime gameTime)
...
telaAtual.Draw(spriteBatch);
37
Dica: E a lista de telas?
No C#, podemos criar listas de objetos com List
Estas listas podem ser acessadas como arrays ou via foreach.
Por exemplo:
List<string> palavras = new List<string>();
palavras.Add("Teste1");
palavras.Add("Teste2");
foreach (string palavra in palavras)
{
MessageBox.Show(palavra);
}
for(int i = 0; i < palavras.Count;i++ )
{
MessageBox.Show(palavras[i]);
}
38
Desafio 2: Criar uma lista de botões
Duas imagens: selecionado / não selecionado
Com evento que é disparado ao executar o botão
Criar lista que gerencia navegação entre botões
39
Uso de classes de apoio ao input para criar
botões e telas
Rodar o projeto e depois remover comentários na
classe clsButtons e executar novamente
Projeto: XNA 3.0 Demo - Botoes e Telas
40
Dica: Organizar Projeto!
Atual
Organizado
Content.Load<Texture2D>(@“Botoes\blackBall“)
Content.Load<Texture2D>(@“Telas\Tela_Inicial")
Content.Load<Texture2D>(@"blackBall“)
Content.Load<Texture2D>(@"Tela_Inicial")
41
Exemplo de projeto organizado
Projeto: XNA 3.0 Demo - Projeto organizado
42
Perguntas?
43
Download

XNA Game Studio Express Deep Dive