Java ME – GameAPI

O que é a Game API?

Junto com o MIDP 2.0 foi criada a Game API, que é uma biblioteca com classes preparadas para a criação de componentes de jogos, como personagens, movimentação, cenários e ciclo de jogo, principalmente para os jogos de ação.

Game API

Qual a diferença do Canvas e do GameCanvas? Qual usar?

O Canvas é um Displayable de baixo nível, onde não há nenhuma funcionalidade pronta, devendo o programador se preocupar desde o desenho da tela aos tratamentos de eventos, porém esta é a grande vantagem do Canvas, pois tudo está nas mãos do programador. A Game API extendeu o Canvas e criou o GameCanvas, com algumas caracteristicas diferentes e mais adequadas a jogos de ação, como a independência dos eventos e o desenho da tela em segundo plano.
Veja a tabela abaixo onde são mostradas como realizar tarefas com ambos:

Característica Canvas GameCanvas
Desenhar na Tela método paint(Graphics), chamado pelo repaint() em qualquer método, em segundo plano, depois basta descarregar a tela de uma única vez pelo método flushGraphics()
Perceber tecla tratamento do evento quando ocorre, sem muito controle do programa pode ser lido a qualquer momento, a pedido do programa pelo método getKeyStates()
Ciclo de Jogo Devido aos itens acima, em geral é controlado por eventos e pode ter atrasos nos movimentos É mais direto, tendo o controle de todos os elementos no momento que for necessário.
Quando usar Programas em que as atividades devem ser executadas pelo acionamento de teclas (eventos) e com pouca exigência gráfica. Programas com maior qualidade de desenho e controle de atividades deve ser preocupação do programa

Código fonte típico de uma subclasse Canvas

public class Tabuleiro extends Canvas implements Runnable {
   // definição de atributos
   public Tabuleiro(){
     // Construtor
   }
   public void run() { // Ciclo de Jogo -> sem eventos
     while(true) {
       recalcula(); // método que recalcula posições
       verifica(); // método para verificar condições
       repaint(); // atualiza tela do jogo
       pausa(); // método para controle de tempo
     }
   }
   public void paint(Graphics g) {
     // código para o redesenho da tela
   }
   protected void keyPressed(int keyCode) {
     // tratamento dos eventos de tecla pressionada
   }
   protected void keyReleased(int keyCode) {
     // tratamento dos eventos de tecla solta
   }
   protected void keyRepeated(int keyCode) {
     // tratamento dos eventos de tecla mantida pressionada
   }
   protected void recalcula(){
     // realiza os cálculos de novas posições
   }
   protected void verifica(){
     // verificar condições de jogo:
     // colisões; conclusão; falha; sucesso
   }
   protected void pausa(){
     // controle de tempo entre os ciclos,
     // mantém a velocidade do jogo
   }
}

Código fonte típico de uma subclasse GameCanvas

public class Cenario extends GameCanvas implements Runnable {
   // definição de atributos
   public Cenario(){
     // Construtor
   }
   public void run() {
     Graphics g=getGraphics(); // obtém o objeto "g", para desenho
     while(true) { // Ciclo de Jogo
       verificaTeclado(); // método que verifica estado das teclas
       recalcula(g); // método que recalcula posições e redesenha tela
       verifica(); // método para verificar condições
       pausa(); // método para controle de tempo
       flushGraphics(); // atualiza tela do jogo
     }
   }
   protected void verificaTeclado() {
     int k= getKeyStates();
     // verifica os estados das teclas (pressionados ou não)
   }
   protected void recalcula(Graphics g){
     // realiza os cálculos de novas posições
     // redesenha os objetos em segundo plano, no objeto "g"
   }
   protected void verifica(){
     // verificar condições de jogo:
     // colisões; conclusão; falha; sucesso
   }
   protected void pausa(){
     // controle de tempo entre os ciclos,
     // mantém a velocidade do jogo
   }
}

Desenhar objetos, paisagens e personagens

a classe abstrata Layer e suas sublasses: Sprite e TiledLayer

A classe que representa elementos visuais na Game API é a classe abstrata Layer, que tem propriedades como posição, largura, altura, visível e serve para desenhar objetos, paisagens e personagens.

Layer é uma classe abstrata e, portanto, deve ser estendida. A Game API tem duas classes filhas de Layer: Sprite e TiledLayer.

Sprite – normalmente usada para representar os personagens de ação, pois permite movimento, animação, transformações e teste de colisões com outros elementos gráficos.

TiledLayer – Normalmente utilizada para construção de cenários, pois permite criar grandes imagens a partir de pequenos blocos de desenho repetidos.

Criando personagens: A Classe Sprite

Numa classe Sprite é possível se colocar uma imagem com diversos momentos do movimento de um personagem, de forma que a simples troca destes momentos se tornem a animação desse personagem.

movimentos do menino animação das gotas personagem dissolvendo

As imagens acima serão desmontadas em seus Sprites e se tornarão um grupo de imagens, responsáveis pelas animações, respectivamente: personagem andando ou parado; chuva; personagem dissolvendo.


Formas de imagens
É ainda tarefa do Sprite rotacionar, espelhar, mover, gerar a animação e testar colisões. Segue abaixo o código base de um Sprite.

public class Ator extends Sprite{
  // atributos do Ator
  public Ator(Image img, int larg, int alt){
    // construtor do Sprite, define imagem e sequencia da animação
    super(img, larg,alt);
    setFrameSequence(sequencia);
  }
  public void movimenta(int x){ // exemplo de método de movimento
    // código para espelhar o sprite
    setTransform(TRANS_MIRROR);
    // código para girar o sprite
    setTransform(TRANS_ROT90);
    setTransform(TRANS_ROT180);
    setTransform(TRANS_ROT270);
    // código cancelar transformações
    setTransform(TRANS_NONE);
    // código para movimentação
    move(x,y);
  }
  public boolean colidiu(Inimigo a){ // exemplo de método de colisão
    // verifica colisão com "Inimigo"
    if (collidesWith(a, true)){
      return true;
    }
    return false;
  }
  public void perdeu(Image img) { // exemplo de método de fim
    // troca imagem e define sequência de fim
    setImage(img, 40, 40);
    setFrameSequence(null);
  }
}

Crie cenários com pequenos blocos de desenho: TiledLayer

Como criar cenários a partir de pequenos blocos de desenho. Assim como Sprite, o TiledLayer recebe como imagem de entrada um desenho composto de diversos pequenos blocos de desenho, que podem ser montados lado a lado, com várias repetições, gerando grandes painéis que serão usados como cenário.

partes de cenario
Imagem com os “tijolos” para montar o cenário
Cenario montado
Cenário montado a partir dos “tijolos” e uma matriz

Método que cria um TiledLayer a partir de uma imagem e uma matriz

private TiledLayer criaFundo() throws Exception {
  Image img = Image.createImage("imagem.png");
  TiledLayer fundo = new TiledLayer(4,12,img,32,32);
  int[] mapa = {
    0, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 1, 4, 4, 3, 0, 0, 0, 0, 1, 2, 2,
    1, 4, 4, 4, 4, 3, 0, 0, 1, 4, 4, 4,
   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
   };
  for (int i=0; i < mapa.length; i++){
    int coluna = i % 12;
    int linha = i / 12;
    fundo.setCell(coluna,linha,mapa[i]);
   }
 return fundo;
}

Para animar a água, basta incluir o seguinte código que troca o “tijolo” da água, na parte de redesenho da tela:

if(anima>7)
  anima=5;
  fundo.setAnimatedTile(-1,anima);
  anima++;

LayerManager

Organizar as diversas camadas de imagens

Classe usada para organizar todos os componentes visuais do jogo, organizando os elementos em camadas, usando um eixo z, onde os primeiros elementos gráficos têm uma prioridade maior.
Seus objetos são criados por um construtor sem parametros:

LayerManager camadas = new LayerManager();

Para inserir elementos na LayerManager usa-se o método append(<Layer>).

camadas.append(fundo);
camadas.append(ator);

No caso acima, o cenário fundo tem maior prioridade e será desenhado na frente do personagem, que pode não ser visualizado.
O correto é inserir os personagens e depois os cenários, exceto em casos em que o cenário deva aparecer na frente do personagem, por decisão estética do jogo.

camadas.append(ator);
camadas.append(fundo);

LayerManager tem outros métodos importantes como: remove(<Layer>), insert (<Layer>, <camada>), paint(<Graphics>, <x>, <y>) e setViewWindow( <x>, <y>, <largura>, <altura>).

Janelas de Visualização

Partes do LayerManager

A movimentação de cenário é implementada com a variação de qual parte da LayerManager estamos vendo, através do método setViewWindow(int x,int y,int largura,int altura) ele cria a janela de visualização, que é uma parte pequena de uma imagem maior armazenada no LayerManager.

Colocando na tela

Resultado do paint(g,x,y)

Para desenhar todo o conteúdo gráfico basta chamar o método paint(<g>, <x>, <y>), que se encarrega de desenhar todos os seus componentes, da janela de visualização definida, no objeto “g” (tipo Graphics) na posição “x,y”.

Usando LayerManager

  private LayerManager camadas;
  private TiledLayer fundo;
  private Sprite ator;
  // no construtor, após criar ator e fundo 
    camadas = new LayerManager();
    camadas.append(ator);
    camadas.append(fundo);
  // no método de movimentação de personagens -> para mover o cenário
    camadas.setViewWindow(x, y, largura, altura);
    //define quadro vísivel: x,y->posição interna do LayerManager no método de desenho da tela
    camadas.paint(g, x, y); 
    // g-> Graphics; x,y->posição na tela onde desenhar o quadro definido acima

Leave a Reply

Your email address will not be published. Required fields are marked *