XNA Game Studio Expressagomes/tjv/praticas/XNAGameStudioExpress...Se for Manual, os recursos...
Transcript of XNA Game Studio Expressagomes/tjv/praticas/XNAGameStudioExpress...Se for Manual, os recursos...
XNA Game Studio ExpressXNA Game Studio ExpressAula 2Aula 2
DesenhoDesenho emem 2D2D
Alexandre Santos LobãoAlexandre Santos Lobãocontatocontato@@AlexandreLobaoAlexandreLobao.com.com
PPóós em Desenvolvimento s em Desenvolvimento de de Jogos EletrônicosJogos Eletrônicos -- IESB IESB
2
Agenda: Aula 2Agenda: Aula 2
RevisãoRevisão
Arquitetura Arquitetura de um de um programa programa XNAXNA
DesenhoDesenho emem 2D2D
““ComponentsComponents”” de um gamede um game
Tratamento Tratamento de input do de input do usuusuááriorio
Divisão Divisão dos dos grupos para grupos para o o projeto da matprojeto da matéériaria
3
XNA FrameworkXNA Framework
RevisãoRevisão -- XNA Game Studio ExpressXNA Game Studio Express
XNA Game Studio XNA Game Studio ExpressExpress
XNA Game Studio ExpressXNA Game Studio Express
Extends C# Express to Extends C# Express to support XNA Framework, support XNA Framework, building game content and building game content and targetingtargeting XboxXbox 360360
XNA FrameworkXNA Framework
.NET Game Framework.NET Game Framework
.NET Framework for 360.NET Framework for 360
Customized .NET Compact Customized .NET Compact Framework Framework
XNA FrameworkXNA Framework
4
RevisãoRevisão: XNA Framework: XNA Framework
PlataformaPlataforma
CoreCore
FrameworkFramework
ExtendedExtended
FrameworkFramework
GamesGames
XACTXACT XINPUTXINPUT XContentXContentDirect3DDirect3D
GraphicsGraphics AudioAudio InputInput MathMath StorageStorage
Application ModelApplication Model Content PipelineContent Pipeline
Starter KitsStarter Kits CCóódigodigo ConteConteúúdodo ComponentesComponentes
Legenda XNA ProvidesXNA Provides NNóós criamoss criamos ComunidadeComunidade
5
ArquiteturaArquitetura de umde um programaprograma XNAXNA
Ao Ao se se criar criar um um projetoprojeto, , são gerados dois arquivossão gerados dois arquivos::
Program.cs
Game1.cs
6
ArquiteturaArquitetura de umde um programaprograma XNAXNA
Program.cs
static void Main(string[] args)
{
using (Game1 game = new Game1())
{
game.Run(); -> Executa o Game Loop
}
}
7
Classe“Game”
É a central da arquitetura XNA
Tem, internamente, um game loop chamado a cada 1/60 de segundo (default)
Propriedade TargetElapsedTime pode mudar esta velocidade
is 1/60th of a second.
8
Arquitetura Arquitetura de umde um programa programa XNAXNA
Game1.csConstrutor – cria os objetos Graphics e Content
public Game1()
{
graphics = new GraphicsDeviceManager(this);
content = new ContentManager(Services);
}
Métodos chamados pela classe Game (“Eventos” do jogo)Initialize()
LoadGraphicsContent(bool loadAllContent)
UnloadGraphicsContent(bool unloadAllContent)
Update(GameTime gameTime)
Draw(GameTime gameTime)
9
ArquiteturaArquitetura de umde um programaprograma XNAXNA
Métodos chamados pela classe Game (1/2)Initialize()
Chamado quando o jogo carrega
Onde se inicializam os recursos não gráficos
Por exemplo, Mousehelper, Som, etc
LoadGraphicsContent(bool loadAllContent)
Chamado sempre que é necessário carregar os recursos (conteúdos) gráficos
Isso pode acontecer no início do jogo, ou quando a janela (no Windows) sai de trás de outra janela, ou quando por algum erro se perde a referência ao dispositivo (device) de video
Quando LoadAllContent é true, é necessário recarregar todo o conteúdo (jncluindo os marcados como “modo de gerenciamento de recursos”automático).
Mais sobre o “modo de gerenciamento de recursos” no próximo slide
10
ArquiteturaArquitetura de umde um programaprograma XNAXNA
O Modo de gerenciamento de recursos É usado nos métodos LoadGraphicsContent e UnloadGraphicsContent
É passado como parâmetro ao carregar vertex buffers, index buffers, textures, e surfaces) pode ser manual ou automático
Se for Manual, os recursos precisam ser recarregados sempre que se perder a referência ao device
Se for Automático, serão automaticamente gerenciados pelo sistema, “existindo” para a aplicação quase sempre (o XNA carrega para a memória caso necessário e já não esteja carregado)
No gerenciamento automático, o XNA fica livre para liberar os recursos na memória da placa caso precise deles, recarregandoquando a aplicação necessitar.
O Gerenciamento Automático é o default, e o usado pela maioria das aplicações.
11
ArquiteturaArquitetura de umde um programaprograma XNAXNA
Métodos chamados pela classe Game (2/2)UnloadGraphicsContent(bool unloadAllContent)
Chamado sempre que é necessário liberar os recursos (conteúdos) gráficos
Quando LoadAllContent é true, é necessário descarregar todo o conteúdo
Update(GameTime gameTime)
Chamado a cada game loop
Onde se coloca a lógica principal do jogo (cálculos)
Recebe um objeto (gameTime) com uma “foto” com informações sobre o tempo no instante da chamada do método
Mais sobre gameTime no próximo slide
Draw(GameTime gameTime)
Chamado a cada game loop
Onde se colocam as rotinas de desenho do jogo
12
ArquiteturaArquitetura de umde um programaprograma XNAXNA
GameTime
Passado como parâmetro para os métodos Update e Draw
Tem propriedades que permitem ler o tempo transcorrido desde a última chamada e desde o início do jogo
Propriedade IsRunningSlowly indica se o TargetElapsedTime não estásendo atingido
O tempo pode se lido em:“Real Time”: tempo em segundos reais (relógio)
É o usado por quase todas as aplicações
“Game Time”: número de passos fixos executados conforme o clock da máquina.
Como não reflete o tempo “de relógio”, a performance de um jogo que se baseie em “Game Time” pode variar conforme a performance da máquina, caso não se tenha cuidado.
Pode ser usado para criar jogos com performance controlável via programa (possivelmente maior), setando-se a propriedade IsFixedTimeStep do objeto Game para false (executa jogo em full speed, ignorando a propriedade TargetElapsedTime)
Exemplos: gameTime.ElapsedRealTime; gameTime.TotalGameTime;
13
DesenhoDesenho dede objetosobjetos 2D2D
14
DesenhoDesenho dede objetosobjetos 2D2D
Na classe game 1:private Texture2D textura;
private SpriteBatch Renderizador2D;
No Método LoadGraphicsContent:override void LoadGraphicsContent(bool loadAllContent)
{
if (loadAllContent)
{ // Para escolher tamanho da janela ou modo fullscreen:
//graphics.PreferredBackBufferWidth = 400;
//graphics.PreferredBackBufferHeight = 400;
//graphics.IsFullScreen = true;
//graphics.ApplyChanges();
textura = content.Load<Texture2D>("xna_thumbnail");
Renderizador2D = new SpriteBatch(graphics.GraphicsDevice);
}
}
15
DesenhoDesenho dede objetosobjetos 2D2D
No Método UnloadGraphicsContent:override void UnloadGraphicsContent(bool unloadAllContent)
{
if (unloadAllContent)
{
textura.Dispose();
Renderizador2D.Dispose();
content.Unload();
}
}
16
DesenhoDesenho dede objetosobjetos 2D2D
No Método Draw:
override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.White);
Renderizador2D.Begin(SpriteBlendMode.AlphaBlend);
Renderizador2D.Draw(textura, Vector2.One, Color.White);
Renderizador2D.End();
base.Draw(gameTime);
}
17
““ComponentsComponents”” de um gamede um game
18
““ComponentsComponents”” de um gamede um game
Coleção Components da Classe Game
Informa ao XNA quais os componentes do jogo
Passos para criar um componente:
1. Criar uma classe derivada de GameComponent
2. Criar um objeto desta classe
3. Adicionar o objeto ao Game usando:this.Components.Add( objeto );
O XNA automaticamente chama os métodos Update e Draw do objeto, se existirem
19
““ComponentsComponents”” de um gamede um game
1. Criar uma classe derivada de GameComponent (1/2)
class clsSprite : GameComponent
{
public Texture2D textura; // sprite texture
public Vector2 posicao; // sprite posicao on screen
public Vector2 velocidade; // velocidade in pixels
public clsSprite(Game game, Texture2D Textura, Vector2 Posicao)
: base(game)
{
textura = Textura;
posicao = Posicao;
}
}
20
““ComponentsComponents”” de um gamede um game1. Criar uma classe derivada de GameComponent (2/2)
public override void Update(GameTime gameTime)
{
// ajusta a velocidade para não sair pelas bordas da tela
if(posicao.X + textura.Width + velocidade.X > this.Game.Window.ClientBounds.Width)
velocidade.X = -velocidade.X; // direita
if (posicao.Y + textura.Height + velocidade.Y > this.Game.Window.ClientBounds.Height)
velocidade.Y = -velocidade.Y; // de baixo
if (posicao.X + velocidade.X < 0)
velocidade.X = -velocidade.X; // esquerda
if (posicao.Y + velocidade.Y < 0)
velocidade.Y = -velocidade.Y; // de cima
// Atualiza a posição
posicao += velocidade;
}
21
““ComponentsComponents”” de um gamede um game
2. Criar um objeto desta classe
3. Adicionar o objeto ao Game
private clsSprite Desenho2D;
...
protected override void LoadGraphicsContent(bool loadAllContent)
{
...
// Load a 2D texture sprite
Desenho2D = new clsSprite(this,
content.Load<Texture2D>("xna_thumbnail"), Vector2.One);
Desenho2D.velocidade = new Vector2(1, 2);
this.Components.Add(Desenho2D);
}
22
““ComponentsComponents”” de um gamede um game
Como não fizemos override do Draw, precisamos atualizar o método Draw da classe Game
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.White);
Renderizador2D.Begin(SpriteBlendMode.AlphaBlend);
Renderizador2D.Draw(Desenho2D.textura, Desenho2D.posicao,
Color.White);
Renderizador2D.End();
base.Draw(gameTime);
}
23
TratamentoTratamento de input do de input do usuusuááriorio
24
TratamentoTratamento de input do de input do usuusuááriorio
Vamos adaptar o demo anterior 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
25
TratamentoTratamento de input do de input do usuusuááriorio
1. Copiar a classe clsSprite para clsPlayer
Dica: use Copy e Paste direto na janela de “Solution Explorer” do C# Express
Além de renomear, vamos incluir na classe:using Microsoft.Xna.Framework.Input;
26
TratamentoTratamento de input do de input do usuusuááriorio
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; // será 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;
}
27
TratamentoTratamento de input do de input do usuusuááriorio
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;
...
}
28
TratamentoTratamento de input do de input do usuusuááriorio
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;
...
}
29
TratamentoTratamento de input do de input do usuusuááriorio
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;
}
30
TratamentoTratamento de input dode input do usuusuááriorio
3. Adicionar o objeto Player ao Game
private clsPlayer jogador;
...
protected override void LoadGraphicsContent(bool loadAllContent)
{
...
// carrega o jogador
jogador = new clsPlayer(this,
content.Load<Texture2D>(“player_xna_thumbnail"),
new Vector2(300, 100));
this.Components.Add(jogador );
}
31
TratamentoTratamento de input dode input do usuusuááriorio
...e finalmente atualizar o método Draw da classe Game
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.White);
Renderizador2D.Begin(SpriteBlendMode.AlphaBlend);
Renderizador2D.Draw(Desenho2D.textura, Desenho2D.posicao,
Color.White);
Renderizador2D.Draw(jogador.textura, jogador.posicao, Color.White);
Renderizador2D.End();
base.Draw(gameTime);
}
32
TratamentoTratamento de input dode input do usuusuááriorio
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
33
TratamentoTratamento de input dode input do usuusuááriorio
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;
}
34
TratamentoTratamento de input dode input do usuusuááriorio
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);
...
}
35
Desafio 1: Navegação entre telas
Criar uma lista de telas
Navegar pela lista de telas
36
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();
}
}
37
Navegando entre telasTambé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(Renderizador2D);
38
Dica: E a lista de telas?
No C#, podemos criar listas de objetos com ListEstas 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]);
}
39
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
40
DicaDica: Input : Input não não tem tem ““memmemóóriaria””
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”)
41
DicaDica: Input : Input não não tem tem ““memmemóóriaria””
Exemplo de uso de Helpers (classes do Abi, do livro “Professional XNA game...”:
1. Incluir Input.cs (modificada) no projeto
2. Chamar Input.Update no update do jogoInput.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();
}
42
Dica: Organizar Projeto!Atual Organizado
content.Load<Texture2D>(@"Texturas\Botoes\blackBall“)
content.Load<Texture2D>(@"Texturas\Telas\Tela_Inicial")
content.Load<Texture2D>(@"blackBall“)
content.Load<Texture2D>(@"Tela_Inicial")
43
DivisãoDivisão dosdos grupos paragrupos para oo projeto da projeto da matmatéériaria
Mini-GDD em duas semanas
44
Perguntas?Perguntas?