Академический Документы
Профессиональный Документы
Культура Документы
Fluxo de telas
Criao e gerenciamento do fluxo de telas
Tcnicas de Scrolling
Tcnica de Side Scrolling
Tcnica de Parallax Scrolling
Animao 2D
Animao 2D
2
Construo de fases
Definio de tiles
Descrio do funcionamento da tcnica
Criao do projeto
Utilizao de arquivos .XML
Contruindo mapas com o XNA Tile Map Editor
Cmera 2D
Criao de uma Cmera 2D
Fsica
Movimento Retilneo Uniforme (MRU)
Lanamento vertical com movimento retilneo uniformemente variado (MRUV)
Lanamento oblquo (deslocamento parablico)
3
Nota:
Websites:
http://kleberandrade.wordpress.com/
http://devtuts.com.br/
Livro:
4
Introduo
5
O que o C#?
Observao:
Orientao a Objetos:
Assim como outras linguagens (Java, C++, etc), o C# uma linguagem orientada a objetos e
oferece suporte aos seus trs recursos bsicos da O.O. :
Encapsulamento:
Herana:
Subclasse: uma classe que um subtipo de uma ou mais classes. Como tal, ela
herda todas as caractersticas de suas superclasses. Em outras palavras, todas
as caractersticas de uma classe podero ser reutilizadas por suas subclasses.
Se a classe B herda de A, ento dizemos que B uma subclasse de A.
6
Superclasse: Uma classe que um supertipo de uma ou mais classes. Como tal,
ela uma classe a partir da qual todas as suas caractersticas so herdadas por
suas subclasses. Em outras palavras, todas as caractersticas de uma
superclasse so reusveis por aquelas classes que so seus subtipos. Se a
classe B herda de A, ento dizemos que A uma superclasse de B.
Polimorfismo:
Vale ressaltar que em C# tudo parte de um tipo (por exemplo: class, interface e
structs), no existem variveis ou funes globais fora deste escopo (como em php), e toda e
qualquer instncia de um tipo um objeto, sendo estes derivados de uma classe base em
comum, neste caso a Object.
Mquina Virtual:
Assim como em Java, as aplicaes em C# rodam sobre uma mquina virtual, a qual
cuida da interao entre o seu sistema (alto-nvel) e o hardware (baixo-nvel), o que
proporciona diversos benefcios como o Garbage Collector (coletor de lixo de memria) e a sua
fcil portabilidade, o que, no entanto, gera uma perda no desempenho do seu sistema.
7
Estrutura de um programa em C# com Hello World:
Para compilar seu primeiro programa em C#, ser necessrio primeiramente criar um
novo projeto. Para isto, v em File > New Project e selecione o Template: Console Application
em Project Types: Visual C#, conforme mostrado na imagem abaixo:
Feito isto, o Visual C# criar seu novo projeto junto a classe Program.cs. Caso a mesma
no abra automaticamente na sua janela, efetue 2 cliques sobre ela na rvore do canto
direito, e mos a obra!
O Visual Studio gera automaticamente o layout principal de cada classe, sendo este
caracterizado da seguinte forma:
8
Historicamente, ao se tratar do ensino de novas linguagens de programao, utiliza-se
de um exemplo com Hello World. Ento, para no fugir a tradio, basta inserir uma linha
entre as chaves da funo Main contendo o seguinte:
Console.WriteLine("Hello World!");
Esta a estrutura principal de uma classe em C#. Utiliza-se o using para usar as
funcionalidades de determinada classe ao seu programa (semelhante ao import em java), o
namespace utilizado para definir um escopo para as classes e variveis globais (geralmente
com o mesmo nome do projeto), sendo a classe nomeada aps o termo class. Uma
observao importante o fato de em C# ser possvel de se criar mais de uma classe em um
nico arquivo.
Neste caso, foi utilizado a palavra static na declarao da funo, o que faz com que
esta funo seja local, podendo ser assim utilizada apenas no arquivo em que for declarada.
9
Tipos suportados em um namespace:
outro namespace
OBS: Para fazer a converso entre os tipos por valores, utiliza-se o objeto Convert. Este
objeto tem diversas funes para realizar as converses em questo. Abaixo voc confere
algumas:
Herana: Para se realizar herana, faz-se da seguinte forma: public class <nome da
classe filha> : <nome da classe pai>.
Estas informaes so suficientes para dar-se incio ao estudo do framework XNA. Para
mais informaes a respeito da linguagem C#, visite o site oficial da Microsoft:
http://msdn.microsoft.com/en-us/library/aa287558.aspx .
10
XNA Game Programming
11
O que XNA?
Vantagens:
Desvantagens:
O framework XNA teve como base o DirectX, tambm desenvolvido pela Microsoft, e
sofreu diversas atualizaes desde o seu surgimento em 2006, sendo tambm integrado a
diversas faculdades de desenvolvimento de jogos e a competies internacionais e nacionais, e
ganhando um espao para jogos de desenvolvedores indies na Xbox Live (rede do console
Xbox 360).
12
Ambiente de desenvolvimento:
Observao:
13
Arquitetura de um programa em XNA
Program.cs:
Note que na criao do objeto game foi utilizado o using, pois ao trmino da
execuo, o mesmo libera automaticamente qualquer informao utilizada
que esteja alocada na memria do computador.
Game1.cs:
Game Loop:
O Game Loop um lao onde ocorrem todas as operaes lgicas e grficas, tendo
anteriormente a inicializao de todos os recursos necessrios para a execuo de um jogo. No
XNA, ele representado basicamente pelos seguintes mtodos:
Game Loop:
Note que o Game Loop em si representado apenas pelos mtodos Update e Draw, os
quais so chamados, respectivamente na ordem citada, a cada lao de execuo.
14
Imagem representando a ordem de execuo de um jogo feito em XNA
Vale ressaltar que a quantidade de laos a serem executados por segundo est
diretamente ligado quantidade de frames por segundo (FPS) do jogo. Se um jogo roda a 60
fps, os mtodos Update e Draw sero executados sessenta vezes a cada um segundo.
OBS: Alm dos mtodos citados, o mtodo construtor de uma classe do tipo Game1 utilizado
para carregar informaes e inicializar dispositivos relacionados execuo do jogo (Game
Loop), como resoluo da tela, inicializao da placa de vdeo, definio do diretrio para os
arquivos externos utilizados no jogo, etc.
Planejamento de um jogo:
Mercado alvo: Nesta etapa escolhida a plataforma, categoria e gnero de seu jogo;
se ele ser feito para algum console ou pc, qual ser o seu pblico alvo (casuais,
hardcores) e o estilo de jogabilidade (plataforma, ao, point-&-click, esportes, etc).
15
Funcionalidades bsicas do XNA
16
Criando um projeto XNA:
Para comear, dever ser criado um novo projeto que utilize o framework XNA no
Visual Studio C# 2010. Para isto, v em File > New Project e selecione o Template: Windows
Game em Project Types: Visual C#, conforme mostrado na imagem abaixo:
Content Pipeline:
O Content Pipeline um dos recursos mais interessantes do XNA, pois reune e trata
em um nico espao todos os arquivos externos utilizados em um projeto, ou seja, no precisa
se preocupar em adaptar arquivos de udio, vdeos, imagens e etc para os tornar compatveis
com o seu jogo.
Formatos de udio: XAP (projeto de audio gerado pelo XACT Tool), WAV, MP3 e WMA
Fontes: SpriteFont (Arquivo XML usado pelo XNA onde voc pode descrever as
caracteristicas da fonte usada, como: tamanho, tipo, etc)
XML: Suporta arquivos .XML que podem ser usados para armazernar dados do jogo
Shaders: Suporta arquivos .FX que so usados para descrever efeitos na renderizao
17
de modelos 3D ou 2D.
Vdeo (a partir do XNA 3.1): .WMV devidamente codificado no Main Profile Series 9.
Content.RootDirectory = "Content";
A varivel (objeto de uma classe) Content uma das variveis globais nativas do XNA,
sendo ela a responsvel pelo tratamento dos arquivos utilizados.
Para carregar um certo dado presente no seu Content, utiliza-se o mtodo Load da
seguinte maneira:
variavel = Content.Load<Tipo>(@"Caminho");
O Tipo representa o tipo (o mesmo da varivel) para o qual o objeto Contet dever
carregar o arquivo, podendo esse ser uma Texture2D, Song, SoundEffect, dentre outros os
quais sero citados mais abaixo. O Caminho nada mais do que o caminho at o arquivo que
deseja carregar, sendo a extenso do arquivo (.jpg, .png, .mp3, etc) no descrita, pois ao
compilar o jogo, o compilador converte todos os arquivos do content para o formato .xnb.
textura = Content.Load<Texture2D>(@"Sprites\ball");
18
Mtodos de inicializao e finalizao:
Alm dos dois mtodos citados, as classes que herdam a Game do XNA possuem um
mtodo construtor, no qual geralmente se define a resoluo e ttulo da janela do jogo, se
inicializa a interao com a placa de vdeo e define o diretrio raiz para os arquivos externos
de um projeto, dentre outras opes.
GameTime:
19
Sistema de coordenadas 2D de uma tela:
O ponto (0,0) dos eixos representa o canto esquerdo superior da janela e os seus
limites so representados pela resoluo, em pixels, do jogo. Ou seja, caso o seu jogo seja
executado em uma resoluo de 800x600, voc estar em uma tela com o limite em X de 800 e
em Y de 600.
Texturas e Sprites:
Antes de tratarmos deste assunto, voc pode conferir abaixo o significado de alguns
jarges que utilizamos com frequncia para grficos em 2D:
Background: O Background a cena de fundo de um jogo, que pode ser composta por
uma ou diversas imagens sobrepostas de forma esttica ou em movimento, gerando
um efeito de scrolling (rolamento).
20
Agora ser mostrado um simples exemplo de como criar e exibir na tela um sprite com sua
respectiva textura. Com o seu projeto criado, crie uma nova classe (clicando com o boto
direito sobre o nome do projeto e seguindo por Add / New Item...). Aqui utilizaremos o
nome clsSprite.
Sero utilizados trs tipos bsicos do XNA para carregar e desenhar a imagem na tela:
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
class clsSprite
{
//Textura do Sprite
public Texture2D textura;
//Varivel para armazenar a posio do sprite na janela
public Vector2 posicao;
//Varivel para armazenar a velocidade de locomoo do sprite
public Vector2 velocidade;
O prximo passo ser adicionar uma imagem ao projeto. Para isso, clique com o boto
direito do mouse sobre o Content de seu projeto e v por Add / Existing Item.... Em
seguida, selecione a imagem desejada e clique em ok.
Feito isto, vamos criar na classe clsSprite um mtodo Draw para desenhar o sprite na
tela.
Este mtodo recebe como paramtro uma vriavel do tipo SpriteBatch, e utiliza a sua
funo Draw para desenhar o sprite.
21
OBS: A funo Draw() do SpriteBatch, alm do bsico (textura, posio e cor base) suporta
alguns parmetro em sua declarao, como escala, rotao, origem, orientao, etc...
Com a classe para tratamento do sprite pronta e com a imagem importada para o
Content do projeto, vamos a classe Game1.cs para renderizar a imagem na tela.
Primeiramente, declaramos as variveis globais do tipo clsSprite e SpritBatch:
A funo Zero do Vector2 retorna o ponto inicial de uma janela (0,0) e os parmetros
(1,1) so usados para que a velocidade de locomoo da imagem seja de uma posio no eixo
X e Y a cada execuo do Game Loop (a ser explicado melhor mais a frente). Por fim, se
adiciona ao mtodo Draw as linhas responsveis por renderizar a imagem na tela:
renderizador.Begin();
jogador.Draw(renderizador);
renderizador.End();
Como mostrado acima, para renderizar-se algo na tela, este trecho do cdigo dever
comear com Begin() e terminar com End(), e ser implementado na classe Game1.cs, a
qual far o processo de renderizao do jogo, neste exemplo.
Se tudo ocorreu bem, ao iniciar o Debugging do seu projeto, dever aparecer uma
janela e uma imagem desenhada na posio inicial da tela.
22
Escrevendo textos na tela:
Com o arquivo aberto, basta configur-lo de acordo com seus critrios, editando os
campos que estiverem entre os <> </>, como nome da fonte, tamanho, negrito, etc.
Utilizaremos aqui para carregar o arquivo uma varivel do tipo SpriteFont (armazena
uma fonte de texto (xml criado no projeto) . Sendo assim, devemos declarar a varivel global
na classe Game1.cs:
fonte = Content.Load<SpriteFont>(@"Verdana");
Feito isto, basta ir ao mtodo Draw e adicionar uma linha para renderizar o seu
texto, conforme abaixo:
23
Controlando um sprite:
Para movimentar um sprite utilizando o teclado, iremos utilizar trs tipos bsicos do
XNA, sendo eles:
Keys: Utilizado para retornar o valor de cada uma das teclas do teclado (para
verificaes).
Para trabalhar com estes mtodos, criaremos uma nova classe, chamada de
clsKeyboard, a qual precisa utilizar a seguinte biblioteca (alm da padro
Microsoft.Xna.Framework):
using Microsoft.Xna.Framework.Input;
class clsKeyboard
{
KeyboardState k;
public clsKeyboard()
{
k = new KeyboardState();
}
if (k.IsKeyDown(Keys.Up))
{
posicao.Y -= velocidade.Y;
}
else if (k.IsKeyDown(Keys.Down))
{
posicao.Y += velocidade.Y;
}
return posicao;
}
}
Como visto acima, a classe possui uma varivel global do tipo KeyboardState, a qual
serve para armazenar o estado do teclado em um determinado momento, e um mtodo
construtor para inicializar a varivel.
O mtodo Update tem como parmetro de entrada trs variveis para realizar suas
operaes. O teclado contm uma captura do teclado naquele momento, a posio a
24
posio na qual o sprite se encontra na janela, e a velocidade a velocidade com que o
sprite se movimenta pela tela.
Alm do que j foi citado acima, o mtodo Update trabalha com a funo
IsKeyDown da varivel do tipo KeyboardState e com o objeto Keys.
Com a classe pronta, podemos voltar a classe Game1.cs e criar um objeto (global) do
tipo clsKeyboard para ento o utilizarmos.
k = new clsKeyboard();
jogador.posicao = k.Update(Keyboard.GetState(),jogador.posicao,
jogador.velocidade);
Caso tudo tenha ocorrido bem, basta pressionar F5 para executar o seu projeto e
testar a movimentao do sprite (neste caso somente no eixo Y).
Debug do cdigo:
Para depurar o seu jogo, alm das prprias ferramentas fornecidas pelo Visual
Studio, pode-se utilizar o console do C# da seguinte forma:
Console.WriteLine("Texto aqui");
Pode-se utilizar tambm uma varivel do tipo string como parmetro para a funo.
25
Coliso entre objetos
26
Coliso entre sprites:
A coliso entre objetos (sprites) parte essencial de um jogo. Com ela, evitamos que
um objeto sobreponha o outro, fazendo assim com que eles colidam. Primeiramente
ensinaremos aqui duas tcnicas de coliso entre sprites, a Bounding Box e Bounding Sphere.
O Bouding Box um sistema de coliso bem simples, no qual ele analisa se o retngulo
(dimenses da imagem) est sendo sobreposto ou sobrepondo um outro retngulo de uma
mesma janela.
A classe Bounding Box (a qual faz parte do XNA framework) contm diversas funes,
mas nos restringiremos a utilizar a Intersects, sendo esta responsvel por verificar se est
havendo coliso entre dois objetos e nos retornar uma varivel do tipo bool como resultado.
27
O mtodo acima retorna os limites do sprite com base na sua posio atual. O primeiro
parmetro passado ao mtodo construtor do BoundingBox trata-se de um Vector3 com a
posio atual do sprite, o segundo trata-se do tamanho nos trs eixos do retngulo que
representa a imagem a partir de sua posio, por isso soma-se a posio atual com as
dimenses da imagem, que podem ser obtidas por meio do mtodo Width e Height de um
Texture2D.
Para utilizar o cdigo, basta ir a classe Game1.cs, criar um novo sprite (ex: jogador2)
e repetir os passos que foram citados acima (no necessariamente precisa utilizar a
movimentao para este segundo, ele pode ficar fixo em um ponto qualquer da janela a sua
escolha). Com o segundo sprite criado, crie tambm um varivel global colisao do tipo bool
(a inicialize como false no mtodo Initialize) e no mtodo Update faa a verificao:
if (jogador.getBoundingBox().Intersects(jogador2.getBoundingBox()))
{
colisao = true;
}
else
{
colisao = false;
}
Estamos utilizando esse verificador para mudar a cor do fundo da janela ao ocorrer a
coliso. Para modificarmos a cor do fundo, vamos at o mtodo Draw da classe Game1.cs
e substitumos a linha que contm o GraphicsDevice.Clear pelas linhas abaixo:
//Caso acontecer a coliso, pinta a tela de vermelho, caso no, pinta de azul
if (colisao)
GraphicsDevice.Clear(Color.Red);
else
GraphicsDevice.Clear(Color.CornflowerBlue);
28
Coliso Bounding Sphere:
29
public BoundingSphere getBoundingSphere()
{
//Retorna os limites (BoudingSphere) do sprite
return new BoundingSphere(new Vector3(this.posicao.X +
this.textura.Width/2, this.posicao.Y + this.textura.Height/2, 0),
this.textura.Width/2);
}
OBS: As variveis do tipo BoundingSphere e BoundigBox tambm possuem uma funo que
pode ser til em diversas outras ocasies. O mtodo em questo o Contains, que retorna
uma enumerao denominada ContainmentType (Contains, Disjoint ou Intersect).
Imagem ilustrando as trs possveis ocorrncias entre dois sprites (fonte: kleberandrade.wordpress.com)
30
Msicas de fundo e efeitos sonoros
31
Msicas de fundo e efeitos sonoros:
A reproduo de udio no XNA d-se de forma bem simples. Basta importar ao seu
Content um arquivo de udio (dos tipos suportados pelo XNA), os carregar nas variveis e
executar o som de acordo com o seu critrio.
32
Com os efeitos sonoros, a reproduo ocorre um pouco diferente, pois no precisa-se
do MediaPlayer. Primeiramente declaramos a varivel global:
//Efeitos sonoros
SoundEffect efeito;
efeito.Play();
Alm da forma citada acima, existe uma sobrecarga da funo Play(), onde voc
pode ajustar o volume, velocidade e balano do efeito:
OBS: Para saber mais detalhadamente a respeito das funes e variveis presentes em cada
objeto ou tipo, basta utilizar o prprio Visual Studio C#, o qual auto-completa mostrando todas
as opes disponveis para aquele objeto.
33
Dicas para criao de um projeto
34
Dicas para criao de um projeto:
O bom senso deve ser bem utilizado. Casos como a construo de inteligncias
artificiais extremamente difceis, ou mesmo invencveis devem ser evitados, alm de definir
controles confortveis e compatveis com o estilo de jogo proposto.
As definies acima faro com que o jogo tenha uma resoluo de 800x600 e seja
executado com a tela em full screen.
Outra modificao que pode ser til a nomeao da janela do jogo em reproduo.
Para modificar o nome basta utilizar a linha abaixo:
O objeto Window faz parte da biblioteca padro do framework, ento ele no precisa
ser declarado ou inicializado por voc, basta modificar seus parmetros para obter o resultado
esperado.
35
Tcnicas de Scrolling
36
Tcnica de Side Scrolling:
O scrolling uma tcnica utilizada para gerar a sensao de se estar deslizando sobre o
contedo de uma imagem, ou seja, enquanto voc joga um game como Mario, o fundo se
move de acordo com a sua movimentao, o que passa a impresso de se estar caminhando
pelo cenrio.
Para gerarmos este efeito, vamos utilizar um dos mtodos de sobrecarga do mtodo
SpriteBatch.Draw, que nos possibilite a especificao de uma determinada rea da textura
que iremos renderizar. A sobrecarga em questo utiliza o seguinte cabealho:
Vamos comear declarando as variveis para a textura e o eixo X (em nosso caso
faremos apenas o scrolling horizontal, para fazer o vertical precisaramos de uma varivel Y):
Texture2D fundo;
//Para determinar o Rectangle.X
int x = 0;
fundo = Content.Load<Texture2D>(@"fundo");
KeyboardState k = Keyboard.GetState();
if (k.IsKeyDown(Keys.Left))
{
x -= 2; //Valor aleatrio. Jamais atribua valores aleatrios a um jogo final.
}
else if (k.IsKeyDown(Keys.Right))
{
x += 2;
}
Aqui devemos ter cautela, pois o valor da varivel X cresce muito rapidamente,
podendo assim ultrapassar o valor suportado por nmeros do tipo inteiro e gerar efeitos
indesejveis ao seu jogo.
37
Abaixo ser sugerido uma forma simples e eficiente para evitar que esse tipo de
problema ocorra:
//Verificao feita para recomear a varivel e evitar que extrapole o limite dos
inteiros
if (x > fundo.Width || x < -fundo.Width)
{
x = 0;
}
O cdigo acima faz a seguinte verificao: quando o valor de X se torna maior (positiva
e negativamente) que a largura da textura, ele volta a ser zero, evitando que o mesmo
extrapole o limite dos inteiros e gerando um resultado visual satisfatrio.
Para finalizar, vamos renderizar a textura na tela, mas para que o side scrolling de fato
ocorra, precisamos utilizar, alm da sobrecarga do mtodo SpriteBatch.Draw, uma das
sobrecargas do mtodo SpriteBatch.Begin no mtodo Draw de sua classe, conforme
abaixo:
renderizador.Begin(
SpriteSortMode.FrontToBack,
BlendState.Opaque,
SamplerState.LinearWrap,
DepthStencilState.Default,
RasterizerState.CullNone
);
OBS: O parmetro BlendState.Opaque faz com que as imagens percam sua transparncia,
tornando-as opacas.
renderizador.Draw(fundo,Vector2.Zero,new Rectangle(x,0,fundo.Width,
fundo.Height),Color.White);
renderizador.End();
A posio inicial da textura a ser desenhada varia de acordo com o X, e logo ao ser
finalizada, o parmetro SamplerState.LinearWarp faz com que o mtodo desenhe o seu
comeo e ligue ao seu final.
38
Imagem com a textura do fundo completa e fixa
39
Tcnica de Parallax Scrolling:
Para gerarmos este efeito, vamos utilizar a mesma tcnica utilizada no Scrolling com
algumas pequenas alteraes.
40
//Inserir no mtodo Update
KeyboardState k = Keyboard.GetState();
if (k.IsKeyDown(Keys.Left))
{
x -= 2; //Valores aleatrios
x2 -= 1;
}
else if (k.IsKeyDown(Keys.Right))
{
x += 2;
x2 += 1;
}
//Verificao feita para recomear a varivel e evitar que extrapole o limite dos
inteiros
if (x > fundo.Width || x < -fundo.Width)
{
x = 0;
}
renderizador.Begin(
SpriteSortMode.FrontToBack,
BlendState.AlphaBlend,
SamplerState.LinearWrap,
DepthStencilState.Default,
RasterizerState.CullNone
);
renderizador.Draw(fundo,Vector2.Zero,new Rectangle(x,0,fundo.Width,
fundo.Height),Color.White);
renderizador.End();
41
Imagem fixa das duas texturas sobrepostas
42
Coliso por Pixels
43
Coliso por Pixels:
A coliso por pixels a forma mais precisa de se verificar a coliso entre duas texturas
em um jogo, porm a mais complexa, pois a verificao feita a partir da transparncia das
imagens utilizadas, analisando pixel por pixel.
Para criarmos o processo de verificao, vamos utilizar um vetor do tipo Color (tipo
responsvel por armazenar a cor de um ou mais pixels) e o mtodo GetData do tipo
Texture2D, para repassar os pixels da textura para a varivel do tipo Color.
//Textura do sprite
Texture2D jogador;
Texture2D jogador2;
OBS: Procure sempre criar variveis constantes para servirem de parmetro na verificao da
movimentao dos sprites, evitando assim inserir diretamente o valor nos algortimos para
movimentao das texturas.
A inicializao das posies fica a seu critrio, utilize os valores que achar melhor (no
mtodo Initialize, com new Vector(x,y)). No mtodo LoadContent, inicialize as texturas e
as demais variveis:
44
A matriz de pixels ser armazenada no vetor do tipo Color, de forma que a
quantidade de linhas da matriz ser definida pela quantidade de pixels verticais da textura, e a
quantidade de colunas ser a mesma que a de pixels horizontais.
Devemos criar tambm um mtodo para fazer a verificao se de fato os pixels esto
colidindo. O chamaremos de ColisaoPorPixel, conforme abaixo:
Ou seja, pela soma da diferena entre o ponto horizontal esquerdo de cada sprite com
o ponto horizontal da posio de verificao em que est o retngulo da interseo (x -
45
retangulo1.Left), com a diferena do ponto vertical no topo do sprite com o ponto vertical
da posio de verificao do retngulo de interseo, vezes a largura do sprite ((y -
retangulo1.Top) * retangulo1.Width), para saber em que linha da matriz imaginria ele se
encontra.
//Jogador 1
if (teclado.IsKeyDown(Keys.D))
posicao.X += velocidade;
if (teclado.IsKeyDown(Keys.A))
posicao.X -= velocidade;
if (teclado.IsKeyDown(Keys.W))
posicao.Y -= velocidade;
if (teclado.IsKeyDown(Keys.S))
posicao.Y += velocidade;
//Jogador 2
if (teclado.IsKeyDown(Keys.Right))
posicao2.X += velocidade;
if (teclado.IsKeyDown(Keys.Left))
posicao2.X -= velocidade;
if (teclado.IsKeyDown(Keys.Up))
posicao2.Y -= velocidade;
if (teclado.IsKeyDown(Keys.Down))
posicao2.Y += velocidade;
colisao = false;
if (ColisaoPorPixel(RetanguloPersonagem1, matrizTexturaJogador,
RetanguloPersonagem2, matrizTexturaJogador2))
{
colisao = true;
}
Passamos como parmetro retngulos e matrizes dos jogadores para o mtodo realizar
a verificao e retornar um booleano como resposta.
Para finalizar, inserimos no mtodo Draw uma verificao para mudar a cor do fundo
quando ocorrer coliso e renderizamos os personagens:
46
//Muda a cor do fundo para vermelho quando uma coliso for detectada
if(colisao)
GraphicsDevice.Clear(Color.Red);
else
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.End();
Imagem ilustrando o retngulo de interseo entre os dois sprites e quando de fato h coliso
Observando as imagens acima, vemos que neste caso no poderamos utilizar a tcnica
com Bounding Box, pois seria detectada uma coliso onde, de fato, no ocorreu.
47
Animao 2D
48
Animao 2D:
Folha de sprites com posies do jogo Super Mario World para Super Nintendo
A imagem acima tem 230x34 pixels, sendo assim temos dez frames de 23x34 pixels.
importante que os quadros estejam bem definidos para o processo de animao ocorrer
de forma satisfatria.
Neste caso criaremos duas novas classes para efetuarmos a animao. Uma classe ser
responsvel por armazenar e realizar a animao de um sprite, enquanto a outra servir para
gerenciar os objetos animados criados com a classe anterior.
49
//Posio da imagem onde deve comear a animao (primeiro frame)
public Point posicaoInicial;
//Se igual a true ativa o Loop da animao
public bool isLoop;
this.textura = textura;
this.framesPorSegundo = framesPorSegundo;
this.tamanhoImagem = colunas;
this.tamanhoFrame = new Point(larguraFrame, alturaFrame);
this.isLoop = false;
this.posicaoInicial = posicaoInicial;
50
public void Draw(ref SpriteBatch renderizador, Vector2 posicao)
{
renderizador.Draw(textura,posicao,new Rectangle(posicaoInicial.X +
(frameAtual * tamanhoFrame.X), posicaoInicial.Y,
tamanhoFrame.X, tamanhoFrame.Y),
Color.White, 0, Vector2.Zero, 1, SpriteEffects.None, 0);
//Os valores 0, 1 e 0 so referentes a rotao, escala e profundidade
}
O cdigo foi bem comentado para melhor entender seus procedimentos. No mtodo
Draw utilizamos uma de suas sobrecargas para definir que rea da folha de sprites desenhar
com base nos parmetros repassados pelo mtodo construtor.
OBS: Como puderam observar, estamos passando o renderizador por referncia ao mtodo
Draw da classe Animacao. A referncia utilizada para economizar espao na memria e
deixar a execuo do mtodo mais eficiente, alm de utilizar exatamente a mesma varivel
utilizada pela classe principal (referncia direta ao endereo de memria em que se encontra).
Resumidamente esta classe fica responsvel por criar na tela uma animao de um
sprite com base na posio inicial e dimenses do frame encontrado na textura e a quantidade
de colunas que existem aps ele (ambas definidas por voc).
Agora iremos criar a classe responsvel por gerenciar as animaes criadas com a
classe acima. A chamaremos de AnimacaoCollectione a daremos o seguinte corpo:
//Cria um Dictionary com uma string como chave e uma Animacao como valor
public Dictionary<string, Animacao> animacoes =
new Dictionary<string, Animacao>();
public AnimacaoCollection() { }
51
public void Draw(ref SpriteBatch renderizador)
{
animacoes[animacaoAtual].Draw(ref renderizador, posicao);
}
}
A classe acima fica responsvel por registrar novas animaes, trocar a animao em
execuo com base em uma chave (string) e chamar seus mtodos Update e Draw.
Com as classes criadas, vamos a classe Game1 para as inserir em nosso jogo.
AnimacaoCollection marioAnimacoes;
Texture2D marioImagem;
//Carrega a textura
marioImagem = Content.Load<Texture2D>(@"mario");
marioAnimacoes.AddAnimacao(correDir, "correDir");
//Cria a animao correr para a esquerda, tendo seu frame inicial a partir do
ponto 115 no eixo x
Animacao correEsq = new Animacao(marioImagem, 10, 5,
23, 34, new Point(115, 0));
marioAnimacoes.AddAnimacao(correEsq, "correEsq");
52
No mtodo Update fazemos a troca entre as animaes de acordo com as teclas
pressionadas e chamamos o Update da varivel do tipo AnimacaoCollection:
KeyboardState k = Keyboard.GetState();
if (k.IsKeyDown(Keys.Left))
{
marioAnimacoes.trocaAnimacao("correEsq");
marioAnimacoes.posicao.X -= 3;
}
else if (k.IsKeyDown(Keys.Right))
{
marioAnimacoes.trocaAnimacao("correDir");
marioAnimacoes.posicao.X += 3;
}
marioAnimacoes.Update(gameTime);
Feito isto basta adicionarmos a chamada para o mtodo Draw da varivel no mtodo
Draw da classe Game1:
renderizador.Begin();
marioAnimacoes.Draw(ref renderizador);
renderizador.End();
53
Fluxo de Telas
54
Criao e gerenciamento do fluxo de telas:
O fluxo de telas indispensvel em qualquer jogo, ele que define e realiza a troca
entre a tela de iniciar e o comeo do jogo ao pressionar Enter por exemplo.
Neste exemplo trabalharemos com duas telas, uma tela de introduo e a outra do
jogo, sendo que ambas sero derivadas (herana) de uma classe chamada Tela.
Imagem ilustrativa da comunicao entre as telas Intro e Game que herdam a classe Tela
Alm das trs classes citadas, utilizaremos uma classe contendo um enumerador para
identificar em que estado se encontra a cena atual.
Primeiramente, crie uma classe chamada Estado e crie um enum conforme abaixo:
Vale ressaltar que o arquivo no deve contar nenhuma classe definida (public class),
tendo ento apenas o enum.
Agora iremos criar a classe Tela como uma classe abstrata (pode ser herdada mas no
instanciada) que ter dois mtodos virtuais (que podem ser sobrepostos pelas suas classes
derivadas com override) Update e Draw:
55
public abstract class Tela
{
// Referncia para o jogo que chamou a cena
protected Game1 game;
protected SpriteBatch renderizador;
A classe tem a funo de receber o objeto do tipo Game1 para ento utilizar os
servios do jogo, neste caso o renderizador.
OBS: O objeto Services faz parte das classes derivadas de Game, que faz parte da estrutura
do XNA. Ele permite a interao de componentes entre as classes que de outras formas seriam
difceis ou impossveis.
Feito isto, criaremos agora as duas classes herdeiras da classe Tela e iremos sobrepor
os mtodos Update e Draw. A primeira chamaremos de Intro e a segunda de Game, conforme
abaixo:
56
base.Draw(gameTime);
}
}
---
public class Game : Tela // Classe para o game
{
private Texture2D textura;
Com as classes criadas, vamos a classe Game1 e declaramos duas novas variveis
globais, sendo uma do tipo Dictionary e outra do tipo Estado (criado por ns):
//Dicionrio de cenas
Dictionary<Estado, Tela> telas;
//Cena atual do jogo
Estado telaAtual;
Agora iremos criar na classe Game1 um mtodo para fazer a troca entre as telas do
jogo:
57
case Estado.Game:
// Adiciona a cena de jogo ao dicionrio
this.telas.Add(Estado.Game, new Game(this));
break;
}
}
E por fim, adicionamos as trocas a serem realizadas pelas classes Intro e Game ao
pressionar as teclas Enter e Esc:
Feito o passo a passo, basta compilar e executar o cdigo para testar o resultado final.
58
Contruo de fases
59
Definio de Tiles:
Essa tcnica conhecida como TileMap, e foi desenvolvida devido a falta de espao
nas mdias de armazenamento e poder de processamento na poca de seu surgimento, onde
utilizar grandes imagens como cenrios era invivel.
Tileset: Paleta de imagens contendo diversos tiles. Utilizada para construo dos
mapas.
Layer: Cada layer representa uma camada de tiles, ou seja, em um jogo podemos ter
mais de um layer (tiles sobrepondo outros tiles).
Primeiramente define-se os tiles que sero utilizados, com seu tamanho, imagem e
posio:
60
Logo aps se monta um tilemap com especificaes da posio de cada tile (com base
em sua numerao e/ou posio) que compor o cenrio:
61
Criao do projeto:
Para criarmos e desenharmos um mapa com tiles criaremos duas classes, uma
chamada Tiles e outra chamada Mapa.
A imagem utilizada em nosso exemplo contm duzentos e cinquenta e seis tiles, cada
um com dimenses de 32x32. Criaremos um tilemap (matriz) com 15x15 tiles, ou seja, ter 480
pixels de largura e altura.
A comear pela classe Tile, criaremos trs variveis globais, um mtodo construtor
para inicializ-las e um mtodo para verificar se houve coliso entre o tile e um outro
retngulo qualquer:
Cada tile formado por um retngulo de uma imagem maior, sendo este inicializado
no mtodo construtor com os pontos x e y em que se encontra o tile na tileset e a sua
largura e altura.
62
As variveis tipo e andavel vo servir para verificar se podemos passar ou no
sobre o tile, sendo que o tipo a numerao que utilizamos em nossa matriz (tilemap).
O mtodo Collide far a verificao de uma possvel coliso entre dois retngulos
(semelhante ao Bounding Box).
O mapa que utilizaremos uma matriz com dimenses de 15x15, disposta da seguinte
forma:
{ 147, 148, 148, 148, 148, 148, 145, 147, 148, 148, 148, 148, 148, 145, 146 },
{ 86, 86, 142, 86, 142, 86, 86, 86, 86, 86, 142, 86, 86, 142, 87 },
{ 86, 86, 86, 86, 142, 86, 86, 86, 86, 159, 86, 86, 86, 86, 87 },
{ 0, 0, 85, 86, 86, 87, 0, 0, 85, 86, 86, 86, 87, 0, 0 },
{ 0, 0, 85, 142, 86, 103, 0, 0, 101, 86, 142, 86, 103, 0, 0 },
{ 0, 0, 101, 102, 103, 0, 0, 0, 0, 101, 102, 103, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 70, 72, 0, 0, 0 },
{ 0, 221, 0, 0, 223, 0, 0, 0, 119, 119, 142, 121, 122, 0, 0 },
{ 0, 221, 0, 0, 223, 0, 0, 0, 139, 86, 159, 86, 144, 0, 0 },
{ 0, 237, 238, 238, 239, 0, 0, 0, 139, 86, 86, 137, 103, 0, 0 },
{ 0, 237, 238, 238, 239, 0, 0, 0, 101, 102, 102, 138, 0, 0, 0 },
{ 0, 253, 254, 254, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
Cada nmero da matriz acima representa um dos tiles de nossa tileset, a comear do
0 e finalizando com o 255 (256 no total).
63
//Mtodo construtor para inicializar as variaveis
public Mapa(Texture2D tileset, int linhas, int colunas,
int tileLargura, int tileAltura)
{
this.linhas = linhas;
this.colunas = colunas;
this.tileLargura = tileLargura;
this.tileAltura = tileAltura;
this.tiles = new Tile[linhas, colunas];
this.tileset = tileset;
}
O mtodo acima inicializa nosso array e passa a ele todas as posies dos tiles de nossa
tileset.
Criaremos mais dois mtodos, desta vez para carregar nosso mapa (matriz) e definir a
posio de cada tile em nossa tela e um outro para percorrer a nova matriz gerada e desenhar
um de cada vez em nossa janela:
64
throw new Exception("Matriz no possui a mesma dimenso do
Mapa");
}
//testa se a imagem dos tiles foi carregada
if (this.tileset == null)
{
throw new Exception("Imagem do mapa no foi carregada");
}
//gera os frames dos tiles
this.GerarTileFrames();
//posio x do tile
int x = 0;
//posio y do tile
int y = 0;
//Tipo do tile que vai ser lido da matriz (inicializa com -1)
int tipo = -1;
//indica se o tile pode ser atravessado
bool andavel = true;
65
public void Draw(ref SpriteBatch renderizador)
{
for (int i = 0; i < this.linhas; i++)
{
for (int j = 0; j < this.colunas; j++)
{
Rectangle destino = new Rectangle(
this.tiles[i, j].retangulo.X,
this.tiles[i, j].retangulo.Y,
this.tileLargura,
this.tileAltura);
renderizador.Draw(this.tileset, destino,
this.tileFrames[frame], Color.White);
}
}
}
Mapa mapa;
//estrutura do mapa
int[,] matrizMapa =
{
{ 148, 149, 149, 149, 149, 149, 146, 148, 149, 149, 149, 149, 149, 146, 147 },
{ 87, 87, 143, 87, 143, 87, 87, 87, 87, 87, 143, 87, 87, 143, 87 },
{ 87, 87, 87, 87, 143, 87, 87, 87, 87, 159, 87, 87, 87, 87, 87 },
{ 1, 1, 86, 87, 87, 88, 1, 1, 86, 87, 87, 87, 88, 1, 1 },
{ 1, 1, 86, 143, 87, 104, 1, 1, 102, 87, 143, 87, 104, 1, 1 },
{ 1, 1, 102, 103, 104, 1, 1, 1, 1, 102, 103, 104, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 70, 71, 72, 1, 1, 1 },
{ 1, 222, 1, 1, 224, 1, 1, 1, 120, 121, 143, 122, 123, 1, 1 },
{ 1, 222, 1, 1, 224, 1, 1, 1, 141, 87, 159, 87, 144, 1, 1 },
{ 1, 238, 239, 239, 240, 1, 1, 1, 141, 87, 87, 138, 104, 1, 1 },
{ 1, 238, 239, 239, 240, 1, 1, 1, 102, 103, 103, 139, 1, 1, 1 },
{ 1, 254, 255, 255, 256, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
};
//largura do tile
const int LARGURA_TILE = 32;
//altura do tile
const int ALTURA_TILE = 32;
//largura da tela
const int LARGURA_TELA;
//altura da tela
const int ALTURA_TELA;
66
No mtodo construtor (Game1) calculamos a resoluo da tela de acordo com o
tamanho da matriz e dos pixels (dimenso do mapa) e com base no resultado mudamos a
resoluo da janela:
//Cria o mapa
this.mapa = new Mapa(Content.Load<Texture2D>("tiles"),matrizMapa.GetLength(0),
matrizMapa.GetLength(1), LARGURA_TILE, ALTURA_TILE);
//Carrega o mapa
this.mapa.CarregarMapa(this.matrizMapa);
this.spriteBatch.Begin();
//Desenha o mapa na tela
this.mapa.Draw(ref this.spriteBatch);
this.spriteBatch.End();
OBS: A tcnica ensinada nos permite trabalhar com apenas um layer de tiles. Para criarmos um
segundo ou terceiro layer precisaramos construir uma nova matriz com o novo layer, declarar
um novo objeto do tipo Mapa e o desenhar sob ou sobre o layer atual no mtodo Draw,
ou ento modificar a classe Mapa para que suporte mais que um.
67
Utilizao de arquivos .XML:
Antes de continuarmos com o estudo dos tiles, precisamos saber melhor a respeito da
utilizao de arquivos .XML em um projeto no XNA (O editor de mapa que usaremos mais
adiante trabalha com este formato).
OBS: O xna tem suporte nativo a arquivos .xml, desde que sigam um padro pr-estabelecido
em sua escrita, o que no o caso do arquivo gerado pelo editor de mapas que usaremos.
Com o nosso arquivo .xml gerado, o copiamos para a pasta Debug de nosso projeto.
Vamos agora a nossa classe que desejamos realizar a leitura e declaramos uma varivel para a
operao (aps importar a biblioteca System.Xml):
XmlTextReader leitorxml;
Alm da leitura convencional podemos ler e salvar aquivos serializveis, o que facilita
bastante todo o processo. Abaixo uma pequena descrio a respeito da serializao:
De forma genrica a serializao uma tcnica usada para persistir objetos , ou seja :
gravar objetos em disco , fazer a transmisso remota de objetos via rede , armazenar os
objetos em um banco de dados e/ou arquivos (binrios , xml, etc.)
Serializar nada mais do que colocar os valores que o objeto est utilizando juntamente
com suas propriedades de uma forma que fique em srie (sequencial) . Fazendo isto estamos
tornando o objeto Serializable, e, tornando um objeto Serializable, estamos atribuindo essa
qualidade a ele, e dando privilgios para que o mesmo possa ser gravado em disco ou enviado
por rede.
68
A serializao o processo de armazenar um objeto , incluindo todos os atributos pblicos
e privados para um stream. (http://www.macoratti.net/vbn_seri.htm)
serializer.Serialize(stream, data);
File.Open(filename, FileMode.OpenOrCreate);
Onde o filename uma string, e o modo da operao de abertura e criao (caso no exista).
data = (TIPO)serializer.Deserialize(stream);
69
Construindo mapas com o XNA Tile Map Editor:
O XNA Tile Map Editor uma ferramente livre desenvolvida pelo programador
Armando Alva da desenvolvedora NandoSoft e pode ser baixada gratuitamente pelo seu site
(http://www.nandosoft.com/).
Ao iniciar o programa, ser aberta a tela acima com um espao para criarmos nosso
mapa. Para modificarmos as dimenses do mapa e a quantidade de layers que utilizaremos,
vamos a janela Resize Map atrves do caminho Edit/Resize Map.
70
Para modificarmos o tamanho de um tile, vamos em Edit / Change Tile Size (em
nosso mapa manteremos o tamanho padro de uma tileset, ou seja, 32):
Com o tamanho dos tiles e a dimenso definidos, vamos importar uma tileset para
desenharmos nosso mapa. Para importar uma tileset, vamos em File / Load Tileset e
selecionamos a tileset desejada.
Com a tileset carregada voc pode desenhar seu mapa utilizando as opes na barra
abaixo do menu, dentre as quais voc pode definir o layer que deseja desenhar, se utilizar o
pincel, o marcador, o balde de tinta ou a borracha.
71
Com o mapa pronto, basta clicar em Options / Export to XML e selecionar o diretrio
que deseja salvar o arquivo. Lembrando que para utilizar esse arquivo em seu projeto, o
mesmo deve ser posto dentro da pasta Debug.
OBS: O XNA Tile Map Editor conta com uma opo para selecionar os locais em que haver
coliso no seu mapa, o mesmo utilizado como o marcador do pincel e pode ser selecionado
na barra de opes.
Para utilizarmos o arquivo xml gerado pelo programa criaremos uma nova classe
CarregarMapaXML e faremos algumas alteraes nas classe Mapa e Tile mostradas
anteriormente.
public Tile(int tipo, bool andavel, bool transparente, int x, int y, int
larguraTile,
int alturaTile)
{
this.tipo = tipo;
this.andavel = andavel;
this.retangulo = new Rectangle(x, y, larguraTile, alturaTile);
this.transparente = transparente;
}
Agora modificaremos a classe Mapa para que aceite mais de um layer, dentre outras
pequenas alteraes que podem ser conferidas abaixo:
72
//Largura do tile
public int tileLargura;
//Lista de matrizes de inteiros (para os layers)
public List<int[,]> matrizLayer;
//Matriz para locais com coliso ativa
public int[,] matrizColisao;
//posio x do tile
int x = 0;
//posio y do tile
int y = 0;
//Tipo do tile que vai ser lido da matriz (inicializa com -1)
int tipo = -1;
//indica se o tile pode ser atravessado
bool andavel = true;
//Indica se o espao do tile vai ser desenhado
73
bool transparente = false;
//O mtodo Draw desenha apenas o layer que for passado como paramtro
public void Draw(ref SpriteBatch batch, int layer)
{
for (int i = 0; i < this.linhas; i++)
{
for (int j = 0; j < this.colunas; j++)
{
Vector2 destino =
new Vector2(this.tiles[layer][i, j].retangulo.X,
this.tiles[layer][i, j].retangulo.Y);
74
Os objetos do tipo List<> utilizados funcionam como um vetor dinmico, ou seja,
criam uma lista indexada que pode receber novos valores em novas posies. Em nosso caso
declaramos listas de matrizes.
class CarregarMapaXML
{
#region Variveis Globais
XmlTextReader mapaxml;
bool layer1Ativo;
bool layer2Ativo;
bool layer3Ativo;
bool layerColisaoAtivo;
Mapa mapa;
int contadorLayer;
#endregion
75
#endregion
//L o arquivo xml e nos retorna um objeto do tipo mapa inicializado com os valores
carregados
public Mapa lerMapa()
{
while (mapaxml.Read())
{
//Verifica se o n em que se encontra a leitra igual a uma declarao
<declarao>
if (mapaxml.NodeType == XmlNodeType.Element)
{
switchLinha(mapaxml);
}
}
//Carrega para a matriz de inteiros nossa lista dinmica de coliso
carregarMatrizColisao(listaLayerColisaoX);
return mapa;
case "Height":
mapaxml.Read();
//Inicializa a quantidade de linhas
this.mapa.linhas = Convert.ToInt32(mapaxml.Value);
break;
case "Tile_Size":
mapaxml.Read();
//Inicializa as dimenses do tile (somente quadrados)
this.mapa.tileAltura = this.mapa.tileLargura =
Convert.ToInt32(mapaxml.Value);
break;
case "Layer":
//Caso seja o layer 1
if (Convert.ToInt32(mapaxml.GetAttribute(0)) == 0)
{
this.layer1Ativo = true;
}
76
//Caso seja o layer 2
else if (Convert.ToInt32(mapaxml.GetAttribute(0)) == 1)
{
this.layer1Ativo = false;
this.layer2Ativo = true;
}
//Caso seja o layer 3
else if (Convert.ToInt32(mapaxml.GetAttribute(0)) == 2)
{
this.layer2Ativo = false;
this.layer3Ativo = true;
}
break;
case "CollisionLayer":
//Caso seja o layer de coliso
this.layer1Ativo = false;
this.layer2Ativo = false;
this.layer3Ativo = false;
this.layerColisaoAtivo = true;
break;
case "RowInfo":
mapaxml.Read();
String linha = mapaxml.Value;
//Captura os elementos entre as virgulas da linha
string[] coluna = linha.Split(',');
else if (layer2Ativo)
{
for (int i = 0; i < coluna.Length; i++)
{
//Subtrai 1 pois o Map Editor gera uma matriz com os tiles a partir
do 1 e no do 0
if (Convert.ToInt32(coluna[i]) != -1)
this.listaLayer2Y.Add(Convert.ToInt32(coluna[i]) - 1);
else
this.listaLayer2Y.Add(Convert.ToInt32(coluna[i]));
}
//Adiciona a lista de colunas na lista de linhas
this.listaLayer2X.Add(listaLayer2Y);
//Reseta a lista de colunas
this.listaLayer2Y = new List<int>();
else if (layer3Ativo)
{
for (int i = 0; i < coluna.Length; i++)
{
77
//Subtrai 1 pois o Map Editor gera uma matriz com os tiles a partir
do 1 e no do 0
if (Convert.ToInt32(coluna[i]) != -1)
this.listaLayer3Y.Add(Convert.ToInt32(coluna[i]) - 1);
else
this.listaLayer3Y.Add(Convert.ToInt32(coluna[i]));
}
//Adiciona a lista de colunas na lista de linhas
this.listaLayer3X.Add(listaLayer3Y);
//Reseta a lista de colunas
this.listaLayer3Y = new List<int>();
else if (layerColisaoAtivo)
{
for (int i = 0; i < coluna.Length; i++)
{
this.listaLayerColisaoY.Add(Convert.ToInt32(coluna[i]));
}
//Adiciona a lista de colunas na lista de linhas
this.listaLayerColisaoX.Add(listaLayerColisaoY);
//Reseta a lista de colunas
this.listaLayerColisaoY = new List<int>();
break;
}
}
#endregion
A classe foi devidamente comentada para seu melhor entendimento. Como puderam
observar, a classe foi criada para aceitar at no mximo trs layers, o que pode ser modificado
de acordo com as suas preferncias.
78
Aps finalizar as classes, vamos a classe Game1 para utiliz-las em nosso jogo.
Primeiramente iremos declarar uma varivel global do tipo Mapa para armazenas as
informaes de nosso mapa e as desenhar na janela.
Mapa mapa;
O primeiro parmetro uma string com o nosso arquivo xml e o segundo a nossa
tileset carregada pelo Contet. Chamamos o mtodo lerMapa() e atribumos o seu retorno
a nossa varivel mapa.
mapa.Draw(ref this.spriteBatch,0);
mapa.Draw(ref this.spriteBatch,1);
mapa.Draw(ref this.spriteBatch,2);
Como nosso mapa possui trs layers, fazemos trs chamadas ao mtodo Draw do
nosso mapa. Deixamos desta forma pois podemos gerar efeitos como desenhar nossos
personagens por trs de um determinado layer, fazendo com que, por exemplo, ele passe por
trs de uma rvore
Imagens com mapa gerado em trs layers e o efeito de nosso personagem se posicionar atrs da cabana
79
Cmera 2D
80
Criao de uma cmera 2D:
//Inicializa as variveis
//Recebe o objeto graphics para capturar a altura e largura da janela
public Camera2D(GraphicsDeviceManager graphics, Vector2 posicao_inicial)
{
this.largura = graphics.GraphicsDevice.Viewport.Width;
this.altura = graphics.GraphicsDevice.Viewport.Height;
this.posicao = posicao_inicial;
81
No mtodo Update ns alteramos a posio da cmera de forma que ela acompanhe
a movimentao do personagem, sempre o colocando ao centro da tela.
Ou seja, caso a cmera esteja posicionada nos pontos 200 e 200 de um determinado
cenrio teramos que subtrair da posio original do objeto a posio da nossa camra
(200,200), para ento obtermos o ponto em que ele deve ser desenhado na janela do jogo.
Para finalizarmos, devemos inserir algumas linhas na classe Game1, comeando pela
declarao das variveis globais:
Texture2D jogador;
Vector2 posicao;
Camera2D camera;
jogador = Content.Load<Texture2D>("jogador");
82
No mtodo Update ns atualizamos a posio com base nas teclas pressionadas e
chamamos o mtodo Update da classe Camera2D:
if (teclado.IsKeyDown(Keys.Right))
posicao.X += 5;
if (teclado.IsKeyDown(Keys.Left))
posicao.X -= 5;
if (teclado.IsKeyDown(Keys.Down))
posicao.Y += 5;
if (teclado.IsKeyDown(Keys.Up))
posicao.Y -= 5;
camera.Update(posicao);
this.spriteBatch.Begin();
this.spriteBatch.End();
OBS: Para melhor visualizao do efeito, crie e desenhe um outro objeto na tela e verifique a
alterao de sua posio conforme mover o jogador.
83
Sistema de save e load
84
Salvar e carregar dados de um arquivo:
[Serializable]
public struct SaveGameData
{
public Vector2 posicao;
public int score;
}
Feito isto vamos criar um mtodo para realizar o processo de escrita (salvar) de nossas
informaes. O mesmo utilizar um FileStream com o fluxo para um arquivo e salvar nossas
informaes de forma serializada:
try
{
//Converte a varivel para xml e o salva em um arquivo
XmlSerializer serializer =
new XmlSerializer(typeof(SaveGameData));
serializer.Serialize(stream, data);
}
finally
{
//Encerra o arquivo
stream.Close();
}
}
try
{
//Abre o arquivo em modo de leitura
stream = File.Open(filename, FileMode.Open, FileAccess.Read);
85
//Carrega as informaes do arquivo para a varivel
XmlSerializer serializer = new
XmlSerializer(typeof(SaveGameData));
data = (SaveGameData)serializer.Deserialize(stream);
//Encerra o arquivo
stream.Close();
}
catch
{
//Caso o arquivo no exista, retornar um Exception
throw new Exception("Arquivo no existente");
}
return (data);
}
// Variveis globais
SaveGameData data;
KeyboardState teclado;
// No mtodo Update
KeyboardState tecladoAnterior = teclado;
teclado = Keyboard.GetState();
OBS: A varivel tecladoAnterior utilizada com o mtodo IsKeyUp para impedir que os
mtodos Save e Load sejam chamados repetidas vezes, caso o jogador mantenha a tecla
pressionada.
86
Fsica
87
Movimento Retilneo Uniforme (MRU):
Para gerarmos um MRU em nosso jogo precisamos aplicar a frmula fsica para
calcular a nova posio de nosso objeto (que aprendemos no ensino mdio). A frmula em
questo a seguinte:
S = So + v * t
posicao = Vector2.Zero;
velocidade = 200;
imagem = Content.Load<Texture2D>(@"imagem");
Com os clculos acima fazemos com que o nosso objeto se mova uma distncia
aproximada de 3,2 pixels no eixo X a cada lao, pois a velocidade igual a 200 e o tempo entre
uma execuo e outra aproximadamente 1,6% de um segundo (0,016).
88
Lanamento vertical com movimento retilneo uniformemente variado (MRUV):
s = so + (vo * t) + (a * t)/2
v = vo + a * t
Texture2D textura;
Vector2 posicao;
Vector2 velocidade;
float gravidade;
textura = Content.Load<Texture2D>(@"imagem");
89
Lanamento oblquo (deslocamento parablico):
Tais circunstncias podem ser observadas num simples lanamento oblquo, onde,
desprezando o atrito do ar e demais efeitos o objeto se desloca verticalmente acelerado pela
ao da gravidade local, e, horizontalmente se desloca seguindo velocidade constante.
(Wikipedia.org)
Texture2D imagem;
Vector2 posicao;
Vector2 velocidade;
float gravidade;
imagem = Content.Load<Texture2D>(@"imagem");
90
E por fim adicionamos a lgica para utilizao das frmulas no mtodo Update:
OBS: Para utilizao de outros elementos fsicos, basta aplicar suas frmulas diretamente no
cdigo de seu jogo.
91