quarta-feira, 19 de outubro de 2011

061 - AmareloGameEngine[2]: Importando arquivos para o projeto

Neste post, vamos aprender um pouco sobre os métodos abstratos da engine que devem ser implementados, a sua importância e como adicionar arquivos ao projeto.

3. Importância dos métodos abstratos
Anteriormente vimos que AmareloGameEngine possui quatro métodos abstratos que precisam ser implementados no projeto. Vejamos o que cada um desses métodos faz:
  • initialize() - É usado para carregar os arquivos que mais tarde serão utilizados no jogo [audio, sprites, fontes...]. Tais arquivos precisam ser importados, como será mostrado adiante.
  • loadContent() - É usado para inserir no jogo os arquivos carregados préviamente na initialize.
  • unloadContent() - Em teoria, é usado para remover do jogo os arquivos carregados na loadContent() [particulamente, não sabemos o seu verdadeiro propósito. Vamos deixar essa função um pouco de lado].
  • update(GameTime game) - é usado para atualizar as informações do jogo em andamento (posição do personagem, tempo de jogo...). Toda a lógica do seu jogo é adicionado a função update.
4. Importando os arquivos do jogo
Todos os arquivos que serão usados em seu jogo [imagens, arquivos de audio, fontes] devem ser importados para a pasta Content de seu projeto



  • Na aba SOLUTION EXPLORER, clique com o botão direito em cima de "(***projeto***)Content (Content)" // add // Existing Item


  • Na janela que se abrirá, navegue até a pasta onde estão os itens que você deseja adicionar e selecione - os [Mais de um arquivo podem ser adicionados a vez]. Aperte ENTER [ou clique em ADD] para adiciona - los. [ Como exemplo importarei 3 arquivos: "background_01.png", "char_black.png" e "qqr.wav"]
  • Os arquivos adicionados aparecem aqui

  • Para melhor organizar os arquivos, crie pastas no Content [(***projeto***)Content (Conent) //add //new folder]. Você pode criar uma pasta para IMAGENS, uma para SPRITES e uma para SONS e arrastar os arquivos importados às suas respectivas pastas.



5. Adicionando os arquivos importados ao jogo
Após importar os arquivos, você precisa agora mandar a engine carregar tais arquivos em seu jogo usando a função loadContent()
  • No escopo da classe crie uma lista de sprites

 List \Sprite/ s = new List\Sprite/()  
 //entre sinais de maior e menor - a formatação html do blogger não me permite adicionar tais símbolos  

  • Assim como Java, C# também tem a classe List e sua utilização é similar a Java.
  • Vamos usar "background_01.png" como imagem de fundo do jogo e "char_black.png" para representar o personagem. Use a função Add para carregar na lista tais imagens.
 s.Add(new Sprite("nomeUnico", Content.Load\Texture2D/("caminho\\do\\arquivoSemExtensao"), layer));  


O construtor da classe Sprite pede:
[*] Uma string "nomeUnico" para o arquivo adicionado. Como da para perceber, essa string deve ser única em todo o projeto;
[*] O caminho de Content.Load\Texture2D/("caminho\\do\\arquivoSemExtensao") é o caminho no Solution Explorer do arquivo da sprite a ser adicionada
[*] _layer_ é um valor float entre 0 e 1 que indica a posição da sprite quanto a profundidade da tela. 0 representa o fundo do seu monitor e 1 representa a tela do monitor;

  • Em nosso caso, para carregar o background e a sprite, usaríamos as seguintes linhas:
 s.Add(new Sprite("backg", Content.Load\Texture2D/("Imagens\\background_01"), 0));  
 s.Add(new Sprite("char1", Content.Load\Texture2D/("Sprites\\char_black"), 1));  

  • Para fazer os arquivoas carregados no jogo aparecerem na tela use
 this.graphicsEng.addSprite(s[i])   


Onde:
[*] i representa o índice da lista. A engine acessará a posição s[i] e carregará qualquer arquivo que estiver lá.

  • Fique alerta a ordem de inserção dos itens na lista! Isto afeta o índice que você usará para fazer a chamada da engine e futuras alterações desses arquivos no jogo. Na ordem que inserimos, a chamada da engine seria feita da seguinte forma:
 this.graphicsEng.addSprite(s[0]); //adiciona o background  
 this.graphicsEng.addSprite(s[1]); //adiciona a sprite  

  • Se você não quiser memorizar quais são os índices que correspondem a cada arquivo, defina constantes no escopo da classe:
 public const int BACKGROUND = 0;  
 public const int CHAR1 = 1;  

  • E use - as como índice:
 this.graphicsEng.addSprite(s[BACKGROUND]); //adiciona o background  
 this.graphicsEng.addSprite(s[CHAR1]); //adiciona a sprite  
  • Neste tutorial, como usaremos poucos recursos gráficos, a definição de constantes é desprezível. Mas em jogos mais complexos, tais definições ajudam o programador a não se perder durante o processo de programação do jogo.
  • Agora o nosso código está desta forma:
1:   using System;  
2:  using System.Collections.Generic;  
3:  using System.Linq;  
4:  using Microsoft.Xna.Framework;  
5:  using Microsoft.Xna.Framework.Audio;  
6:  using Microsoft.Xna.Framework.Content;  
7:  using Microsoft.Xna.Framework.GamerServices;  
8:  using Microsoft.Xna.Framework.Graphics;  
9:  using Microsoft.Xna.Framework.Input;  
10:  using Microsoft.Xna.Framework.Media;  
11:  using Amarelo;  
12:  using Amarelo.GameEngine;  
13:  namespace testetutorial  
14:  {  
15:    ///  
16:    /// This is the main type for your game  
17:    ///  
18:    public class testetutorial : Amarelo.AmareloGame  
19:    {  
20:      public const int BACKGROUND = 0;  
21:      public const int CHAR1 = 1;  
22:      List s = new List(); //Cria uma lista de sprites  
23:      public testetutorial(GameConfig cg) : base(cg)  
24:      {  
25:        Content.RootDirectory = "Content";  
26:      }  
27:      ///  
28:      /// This is called when the game should draw itself.  
29:      ///  
30:      ///  
31:  Provides a snapshot of timing values.  
32:      protected override void Draw(GameTime gameTime)  
33:      {  
34:        GraphicsDevice.Clear(Color.CornflowerBlue);  
35:        // TODO: Add your drawing code here  
36:        base.Draw(gameTime);  
37:      }  
38:      protected override void initialize()  
39:      {  
40:        this.inputEngine.KeyPressed += tecla;  
41:        this.inputEngine.KeyReleased += teclaR;  
42:        //throw new NotImplementedException();  
43:      }  
44:      protected override void loadContent()  
45:      {  
46:        s.Add(new Sprite("backg", Content.Load("Imagens\\background_01"), 0)); //Carrega o background na lista  
47:        s.Add(new Sprite("char1", Content.Load("Sprites\\char_black"), 1)); //Carrega a sprite do personagem na lista  
48:        this.graphicsEng.addSprite(s[BACKGROUND]); //adiciona o background  
49:        this.graphicsEng.addSprite(s[CHAR1]); //adiciona a sprite  
50:      }  
51:      protected override void unloadContent()  
52:      {  
53:        //throw new NotImplementedException();  
54:      }  
55:      protected override void update(GameTime time)  
56:      {  
57:        //throw new NotImplementedException();  
58:      }  
59:    }  
60:  }  

  • Salve e teste
  • Agora essa é a nossa tela de jogo no momento: note que o seu personagem não vai cair em queda livre por enquanto. Ainda não colocamos a física do jogo, o que será feito mais adiante.


  • A seguir: captura de teclas de teclado


060 - AmareloGameEngine[1]: Esqueleto do código

Amarelo Game Engine é uma engine de desenvolvimento de jogos para XNA do grupo Interactive Digital Enterteniment [Indigente] da Universidade Federal da Bahia e pode ser baixada direto do repositório SVN do projeto [ procura no google ae... ] mediante um programa apropriado [ para usuários do Windows, recomenda - se TortoiseSVN ]. A engine é desenvolvida em C#

Todo esse tutorial será feito usando Microsoft Visual Studio 2010 Express. Lembre - se de ter instalado este programa mais o XNA.

Neste primeiro post, vamos aprender a criar um projeto no Visual Studio (a coisa mais simples do mundo) e a escrever o esqueleto do código.

1. Criando um novo projeto no Visual Studio
  • FILE // NEW PROJECT
  • VISUAL C# // WINDOWS GAME 4.0


  • No campo NAME, dê o nome do seu jogo [ "testetutorial" por exemplo ]
  • Clique em OK
  • Após tudo isso, a próxima tela deve ser similar a essa...



2. Montando o esqueleto do código
  • Baixe a engine no svn do projeto - use um programa próprio para isso [ TortoiseSVN por exemplo]
  • Na aba SOLUTION EXPLORER //SOLUTION (nome do projeto), clique com o botão direito na pasta REFENCES // ADD REFERENCE


  • Uma janela como essa se abrirá


  • Navegue até "(pasta do checkout) // AmareloGameEngine // bin // x86 // debug", selecione a dll "AmareloGameEngine.dll" e clique em OK


  • O nome AmareloGameEngine aparecerá na pasta REFERENCES



  •  Para importar outros recursos - como a engine de física ou outra engine qualquer - basta repetir os passos acima
Ao criar o projeto, o Visual Studio já gera o esqueleto do código do seu jogo. Mas para usar os recursos da AmareloGameEngine, você precisará importar duas coisas para o projeto: a engine em si e o namespace Amarelo
Agora porque importar o namespace? Sem isso, todas as funções da engine que você usar devem ser seguidas do nome Amarelo [ Amarelo.FadeInOut(), Amarelo.graphicsEngine.addSprite() ]. Com o namespace, apenas o nome da função já basta.
  • No arquivo "Game1.cs", logo nas linhas iniciais do código, existe uma lista de imports do XNA:
 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using Microsoft.Xna.Framework;  
 using Microsoft.Xna.Framework.Audio;  
 using Microsoft.Xna.Framework.Content;  
 using Microsoft.Xna.Framework.GamerServices;  
 using Microsoft.Xna.Framework.Graphics;  
 using Microsoft.Xna.Framework.Input;  
 using Microsoft.Xna.Framework.Media;  
  • Adicione a essa lista o namespace e a engine, respectivamente:
 using Amarelo;  
 using Amarelo.GameEngine; 



  •  Troque a linha...


  •  public class Game1 : Microsoft.Xna.Framework.Game  
    

    • ...por
      public class _nome do projeto_ : Amarelo.AmareloGame  
    

    • e o nome do construtor...
     public Game1()  
    

    • por...
     public _nome do projeto_(GameConfig cg) : base(cg)
    

    • enfim apague a linha
     GraphicsDeviceManager graphics;  
    
    • Na aba SOLUTION EXPLORER // ( nome do projeto ) , clique duas vezes no arquivo "program.cs"
    • Dentro da função main adicione a linha
      Amarelo.GameConfig cg = new Amarelo.GameConfig()  
    

    • e troque a linha
      using (Game1 game = new Game1())  
    

    • ...por
      using ( _nome do projeto_ game = new _nome do projeto_(cg))   
    

    • Salve o projeto (Ctrl+S)  e teste (F5)
    • Ao tentar executar, vc deve se deparar com uma mensagem de erro similar a essa:


    • O erro reporta a não implementação dos métodos abstratos da engine. Na linha
    public class : Amarelo.AmareloGame

    • Clique com o botão direito em Amarelo.AmareloGame e selecione a opção IMPLEMENT ABSTRACT CLASS


    • Essas novas linhas aparecerão no final do código


    • Trata - se dos métodos Initialize(), LoadContent(), UnloadContent e Update(GameTime game). Elas já existem quando você cria um novo projeto no XNA. AmareloGameEngine apenas reimplementa tais métodos. Portanto as linhas de código abaixo, situadas logo após o construtor da classe são dispensáveis. Apague - as do código


         /// 
         /// Allows the game to perform any initialization it needs to before starting to run.  
         /// This is where it can query for any required services and load any non-graphic  
         /// related content. Calling base.Initialize will enumerate through any components  
         /// and initialize them as well.  
         ///   
         protected override void Initialize()  
         {  
           // TODO: Add your initialization logic here  
           base.Initialize();  
         }  
         /// 
         /// LoadContent will be called once per game and is the place to load  
         /// all of your content.  
         ///   
         protected override void LoadContent()  
         {  
           // Create a new SpriteBatch, which can be used to draw textures.  
           spriteBatch = new SpriteBatch(GraphicsDevice);  
           // TODO: use this.Content to load your game content here  
         }  
         /// 
         /// UnloadContent will be called once per game and is the place to unload  
         /// all content.  
         /// 
         protected override void UnloadContent()  
         {  
           // TODO: Unload any non ContentManager content here  
         }  
         ///  
         /// Allows the game to run logic such as updating the world,  
         /// checking for collisions, gathering input, and playing audio.  
         /// 
         /// 
    
    
    
    
    
    Provides a snapshot of timing values.</param>  
         protected override void Update(GameTime gameTime)  
         {  
           // Allows the game to exit  
           if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)  
             this.Exit();  
           // TODO: Add your update logic here  
           base.Update(gameTime);  
         }  
    
    •  Comente as exceções dos métodos abstratos implementados. Eles só servem para lembrar de que é você que vai implementar o código desses métodos. Essa implementação varia com o jogo.
    • Agora nós temos apenas o construtor do projeto, o método Draw(GameTime gameTime) default do projeto e os métodos abstratos da AmareloGameEngine, encerrando assim a construção do esqueleto do código
    1:  /* --- ESQUELETO Game1.cs --- */  
    2:  using System;  
    3:  using System.Collections.Generic;  
    4:  using System.Linq;  
    5:  using Microsoft.Xna.Framework;  
    6:  using Microsoft.Xna.Framework.Audio;  
    7:  using Microsoft.Xna.Framework.Content;  
    8:  using Microsoft.Xna.Framework.GamerServices;  
    9:  using Microsoft.Xna.Framework.Graphics;  
    10:  using Microsoft.Xna.Framework.Input;  
    11:  using Microsoft.Xna.Framework.Media;  
    12:  using Amarelo;  
    13:  using Amarelo.GameEngine;  
    14:  namespace <nome do projeto>  
    15:  {  
    16:    /// 
    17:    /// This is the main type for your game  
    18:    /// 
    19:    public class _nome do projeto_ : Amarelo.AmareloGame  
    20:    {  
    21:       GraphicsDeviceManager graphics;  
    22:      SpriteBatch spriteBatch;  
    23:      public <nome do projeto>(GameConfig cg) : base(cg)  
    24:      {  
    25:        Content.RootDirectory = "Content";  
    26:      }  
    27:      /// 
    28:      /// This is called when the game should draw itself.  
    29:      /// 
    30:      /// Provides a snapshot of timing values.
    31:      protected override void Draw(GameTime gameTime)  
    32:      {  
    33:        GraphicsDevice.Clear(Color.CornflowerBlue);  
    34:        // TODO: Add your drawing code here  
    35:        base.Draw(gameTime);  
    36:      }  
    37:      protected override void initialize()  
    38:      {  
    39:        //throw new NotImplementedException();  
    40:      }  
    41:      protected override void loadContent()  
    42:      {  
    43:        //throw new NotImplementedException();  
    44:      }  
    45:      protected override void unloadContent()  
    46:      {  
    47:        //throw new NotImplementedException();  
    48:      }  
    49:      protected override void update(GameTime time)  
    50:      {  
    51:        //throw new NotImplementedException();  
    52:      }  
    53:    }  
    54:  }  
    55:  /* --- ESQUELETO program.cs --- */  
    56:  using System;  
    57:  namespace __nome do projeto__
    58:  {  
    59:  #if WINDOWS || XBOX  
    60:    static class Program  
    61:    {  
    62:      /// 
    63:      /// The main entry point for the application.  
    64:      /// 
    65:      static void Main(string[] args)  
    66:      {  
    67:        Amarelo.GameConfig cg = new Amarelo.GameConfig();  
    68:        using (_nome do projeto_ game = new _nome do projeto_(cg))  
    69:        {  
    70:          game.Run();  
    71:        }  
    72:      }  
    73:    }  
    74:  #endif  
    75:  }  
    
    • Salve e teste
    • Após todos esses procedimentos, finalmente teremos uma tela azul ( não se trata da BlueScreenOfDeath ) como essa. Clique no X vermelho no canto da janela para fechar.


    quinta-feira, 13 de outubro de 2011

    059 - AmareloGameEngine

    Como já citei anteriormente, Amarelo Game Engine é a engine desenvolvida pela galera do Indigente para os jogos Amarelo e Quatro Mundos.

    Como a engine ainda está em fase de desenvolvimento, em diversos momentos encontramos dificuldades em usa - la. Quatro Mundos é praticamente um laboratório para o Amarelo: tudo aquilo que esperamos que a engine suporte mas não suporta é reportado para a equipe de desenvolvimento da engine para conserto futuro.

    Até eu tento "consertar a engine".

    Por isso como forma de documentação informal da Amarelo Game Engine, para os atuais membos do grupo e futuros indigentes, estou postando este pequeno tutorial de uso, feito com base naquilo que já deu certo.

    99% de tudo o que for postado aqui neste tutorial tem que dar certo (1% não vai dar certo porque ou está em fase de implementação ou não foi implementado).

    sexta-feira, 7 de outubro de 2011

    058 - 4 Mundos[3]: Últimas notícias da sexta

    Nessa semana, eu e Yuri travamos um combate contra o XACT, tentando usa - la no Amarelo. Basicamente tentamos fazer os efeitos de Fade In e Fade Out (aumentar/diminuir o som gradativamente). Nosso problema era acessar o volume do arquivo de audio atual e fazer esse controle. O problema já foi resolvido.

    Falta agora testar isso com os arquivos que serão usados no jogo. Fazer também que a troca de personagens gere o fade out do personagem atual simultaneamente com o fade in do personagem chamado.

    segunda-feira, 3 de outubro de 2011

    057 - SBGames2011[3] - Agora é só diversão e aprendizado

    Sabe OfeDef, uma das nossas submissões no SBGames 2011? Pois bem...

    Fail: o jogo não foi aprovado :'(

    Dessa forma, esse jogo deixa de ser conhecido do público de jogos em geral para se tornar mais uma produção no portifólio do Indigente.

    Mesmo com essa derrota [ fatality ], não vamos parar de produzir. O próprio conceito do jogo já é algo novo ( jogo de tiro com elementos do exército brasileiro, incentivo do patriotismo nacional...). Continuemos com isso até o fim!