J2ME: diferenças entre revisões

Origem: Wikilivros, livros abertos por um mundo aberto.
[edição verificada][edição verificada]
Conteúdo apagado Conteúdo adicionado
Guiwp (discussão | contribs)
Sem resumo de edição
Guiwp (discussão | contribs)
Sem resumo de edição
Linha 5 247: Linha 5 247:
}
}
</syntaxhighlight>
</syntaxhighlight>



== Criando arquivos M3G no Blender ==
== Criando arquivos M3G no Blender ==
Linha 5 253: Linha 5 252:
Neste tutorial vamos ver como criar um arquivo .m3g utilizando o Blender, um software gratuito de modelagem 3D.
Neste tutorial vamos ver como criar um arquivo .m3g utilizando o Blender, um software gratuito de modelagem 3D.


== O programa ==
=== O programa ===


Você pode baixar e instalar gratuitamente a versão completa do Blender em seu site oficial [http://www.blender.org/ www.blender.org].
Você pode baixar e instalar gratuitamente a versão completa do Blender em seu site oficial [http://www.blender.org/ www.blender.org].


== Blender Export for J2ME ==
=== Blender Export for J2ME ===


A partir da versão 2.48 o Blender passou a vir com um exportador para o J2ME, para exportar seu objeto clique '''File -> Export -> M3G (.m3g, java) -> OK'''. Aparecerá uma janela com os seguintes atributos:
A partir da versão 2.48 o Blender passou a vir com um exportador para o J2ME, para exportar seu objeto clique '''File -> Export -> M3G (.m3g, java) -> OK'''. Aparecerá uma janela com os seguintes atributos:
Linha 5 280: Linha 5 279:
** O3D As O3DTGZ
** O3D As O3DTGZ


=== Ligações externas ===
== Ligações externas ==


* [http://java.sun.com/javame/index.jsp Site da Sun]
* [http://java.sun.com/javame/index.jsp Site da Sun]

Revisão das 23h15min de 10 de setembro de 2013

J2ME é uma plataforma da Sun Microsystems que usa a linguagem Java para o desenvolvimento de aplicativos para dispositivos móveis como celulares, palms ou pocketpcs.

Esse Wikibook é destinado ao aprendizado da programação na plataforma J2ME.

Audio

Por faltar instruções
Esta página precisa ser reciclada (discuta).
Ao melhorá-la, você estará ajudando o Wikilivros.
Este livro ou módulo precisa ser formatado segundo o modelo wiki e/ou organizado conforme as convenções do Wikilivros. (discuta)
Por favor ajude a formatar este módulo de acordo com as diretrizes estabelecidas no livro de estilo.
Editor: considere colocar o mês e o ano da marcação.
 import java.io.IOException;
 import java.io.InputStream;
 import javax.microedition.lcdui.Display;
 import javax.microedition.lcdui.Form;
 import javax.microedition.lcdui.Gauge;
 import javax.microedition.media.Manager;
 import javax.microedition.media.MediaException;
 import javax.microedition.media.Player;
 import javax.microedition.media.control.VolumeControl;
 import javax.microedition.midlet.MIDlet;
 import javax.microedition.midlet.MIDletStateChangeException;

 public class SoundTest extends MIDlet implements Runnable
 {
    private Display display;
    private Player player;
    private Form form;
    private Gauge volume;
    private VolumeControl vc;
    private int value=10;
    public SoundTest()
    {
         try
         {
              display = Display.getDisplay(this);
              form = new Form("MP3");
              volume = new Gauge("Volume",true,100,10);
              form.append(volume);
            //  form.setItemStateListener(this);
              display.setCurrent(form);

         }
         catch (Exception ex)
         {
             System.out.println(ex);
         }

    }
    public void startApp() throws MIDletStateChangeException
    {
       playMP3();
       Thread t = new Thread(this);
       t.start();
    }
    public void pauseApp()
    {

    }
    public void destroyApp(boolean unconditional)
    {

    }
    public void playMP3()
    {
        try
        {
           InputStream is = getClass().getResourceAsStream("/t.mid");
           player = Manager.createPlayer(is,"audio/midi");
           player.realize();
           vc = (VolumeControl) player.getControl("VolumeControl");
           player.prefetch();
           if(vc != null)
           {
              vc.setLevel(value);
           }
           player.start();
        }
        catch(IOException ioe)
        {
            ioe.printStackTrace();
        }
        catch(MediaException me)
        {
            me.printStackTrace();
        }
    }

    public void run()
    {
        while (true)
        {
           vc.setLevel(volume.getValue());
            try
           {
              Thread.sleep(20);
           }
           catch (InterruptedException ie)
           {
           }
        }

    }
 }

Canvas

Durante as primeiras lições trabalhamos com a chamada "interface de alto nível", ou seja, aplicávamos os comandos para a interface pré construída no celular executa-las, agora iremos começar a trabalhar com a chamada "interface de baixo nível", ou seja, iremos dar os comandos diretamente para os gráficos, trabalhando com a manipulação de pixels. Para isso iremos usar amplamente a classe Canvas.

Estrutura Canvas

Primeiramente precisamos criar uma classe exclusiva separada da classe principal para trabalhar com o Canvas, essa também será importada do pacote javax.microedition.lcdui, e irá estender a classe Canvas.

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;

public class ClasseMeuCanvas extends Canvas {
}

Agora devemos colocar o método paint() que entra como parâmetro um objeto da classe Graphics que irá controlar o que irá ser exibido no canvas.

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;

public class ClasseMeuCanvas extends Canvas {
    public void paint(Graphics meuGrafico){
    }
}

Agora na classe principal, a chamada do objeto da ClasseMeuCanvas é feita do mesmo modo das chamadas dos outros objetos, através de um método do objeto Display, vejamos abaixo o conteúdo dos 2 arquivos, o ClasseMeuCanvas.java e o ClassePrincipal.java.

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;

public class ClasseMeuCanvas extends Canvas {
    public void paint(Graphics meuGrafico){
    }
}
//arquivo ClassePrincipal.java
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class ClassePrincipal extends MIDlet {
    Display meuDisplay = Display.getDisplay(this);
    ClasseMeuCanvas meuCanvas = new ClasseMeuCanvas();

    public void startApp() {
        meuDisplay.setCurrent(meuCanvas);
    }
    public void pauseApp() {
    }
    public void destroyApp(boolean unconditional) {
    }
}

Desenhando objetos primitivos

Agora que já sabemos a estrutura de um canvas, vamos desenhar algo na tela, para isso iremos usar o objeto do tipo Graphics e aplicar sobre ele métodos pré-fabricados pelo J2ME que irão desenhar coisas simples na tela como strings, retângulos, arcos, triângulos, etc. Esses comandos ficarão dentro do método paint().

Desenhando uma linha

Vamos desenhar uma linha simples, vamos usar o método drawLine() da classe Graphics, ele irá receber 4 atributos: o 1ª será o pixel x de onde a linha vai começar, o 2º será o pixel y de onde a linha vai começar, o 3º o pixel x onde a linha vai terminar, o 4º será o pixel y onde a linha vai terminar.

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;

public class ClasseMeuCanvas extends Canvas {
    public void paint(Graphics meuGrafico){
        meuGrafico.drawLine(30, 40, 70, 90);
    }
}

Desenhando um retângulo

Vamos desenhar um retângulo, vamos usar o método drawRect() da classe Graphics, ele irá receber 4 atributos: o 1ª será o pixel x de onde o retângulo vai começar, o 2º será o pixel y de onde o retângulo vai começar, o 3º será a largura em pixels do retângulo, o 4º será a altura em pixels do retângulo.

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;

public class ClasseMeuCanvas extends Canvas {
    public void paint(Graphics meuGrafico){
        meuGrafico.drawRect(20, 30, 60, 70);
    }
}

Desenhando um retângulo cheio

Você viu anteriormente como desenhar um retângulo na tela, só que no exemplo anterior esse retângulo era oco por dentro, ou seja, você só desenhou as bordas do retângulo, vamos agora fazer um retângulo totalmente pintado por dentro, para isso vamos usar o método fillRect() da classe Graphics, ele irá receber os mesmos atributos do método drawRect(): o 1ª será o pixel x de onde o retângulo vai começar, o 2º será o pixel y de onde o retângulo vai começar, o 3º será a largura em pixels do retângulo, o 4º será a altura em pixels do retângulo.

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;

public class ClasseMeuCanvas extends Canvas {
    public void paint(Graphics meuGrafico){
        meuGrafico.fillRect(20, 30, 50, 60);
    }
}

Desenhando uma String

Vamos desenhar uma string, note que não vamos simplesmente colocar a string na tela, vamos desenhá-la, apesar disso o J2ME já vem com uma fonte string padrão para o Canvas. Vamos usar o método drawString() da classe Graphics, ele irá receber 4 atributos: o 1º será o texto da string, o 2º será o pixel x de onde vai ser desenhado, o 3º será o pixel y de onde vai ser desenhado, o 4º será a "raiz" do objeto, ou seja, onde será a referência dos pixels x e y.

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;

public class ClasseMeuCanvas extends Canvas {
    public void paint(Graphics meuGrafico){
        meuGrafico.drawString("Texto da string", 50, 100, Graphics.LEFT|Graphics.TOP);
    }
}

Nesse caso a raiz do pixel x está no ponto esquerdo do objeto (Graphics.LEFT), e a raiz do pixel y está no ponto acima do objeto (Graphics.TOP). Você também pode colocar a raiz do pixel x na direita (Graphics.RIGHT) ou no centro (Graphics.HCENTER), e a raiz do pixel y na parte de baixo (Graphics.BOTTOM) ou no centro (Graphics.VCENTER).

Colocando uma cor

Você pode setar cores para desenhar objetos com cores diferentes, para isso use o método setColor() da classe Graphics entrando como parâmetro os valores das cores vermelho, verde e azul respectivamente.

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;

public class ClasseMeuCanvas extends Canvas {
    public void paint(Graphics meuGrafico){
        meuGrafico.setColor(255, 0, 0);
        meuGrafico.drawRect(50, 50, 20, 30);
    }
}

Pegando uma cor

Para pegar uma cor vamos utilizar o método getColor() da classe Graphics que irá retornar um inteiro com os valores RGB agrupados.

Primeiro vamos criar a variável inteira que irá armazenar a cor.

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;

public class ClasseMeuCanvas extends Canvas {
    int corPega;
    public void paint(Graphics meuGrafico){
    }
}

Agora vamos setar alguma cor através do método setColor().

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;

public class ClasseMeuCanvas extends Canvas {
    int corPega;
    public void paint(Graphics meuGrafico){
        meuGrafico.setColor(255, 128, 64);
    }
}

Agora vamos utilizar o método getColor(), e armazenar o resultado na variável corPega.

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;

public class ClasseMeuCanvas extends Canvas {
    int corPega;
    public void paint(Graphics meuGrafico){
        meuGrafico.setColor(255, 128, 64);
        corPega = meuGrafico.getColor();
    }
}

O valor obtido na variável corPega é equivalente ao número hexadecimal agrupado FF, 80, 40 que se traduz em inteiro como 255, 128, 64.

Desenhando uma imagem

Vimos anteriormente as primitivas que o J2ME nos oferece, agora vamos mostrar na tela uma imagem feita por nós mesmo. Primeiro crie a sua imagem em algum editor externo a sua escolha, salve a imagem e coloque no mesmo diretório onde se localiza o arquivo ClasseMeuCanvas.java.

Agora primeiramente vamos incluir o pacote java.io que contém o tratamento de exceção.

//arquivo ClasseMeuCanvas.java
import java.io.*;
import javax.microedition.lcdui.*;

Agora criar uma variável da classe Image.

//arquivo ClasseMeuCanvas.java
import java.io.*;
import javax.microedition.lcdui.*;

public class ClasseMeuCanvas extends Canvas {
    Image minhaImagem;
    public void paint(Graphics meuGrafico){
    }
}

Agora vamos usar o construtor para inicializar o objeto minhaImagem. Para isso vamos jogar a exceção.

//arquivo ClasseMeuCanvas.java
import java.io.*;
import javax.microedition.lcdui.*;

public class ClasseMeuCanvas extends Canvas {
    Image minhaImagem;

    ClasseMeuCanvas throws Exception {
    }
    public void paint(Graphics meuGrafico){
    }
}

Agora dentro do construtor vamos inicializar o objeto minhaImagem utilizando o método createImage() da classe Image, ele receberá como parâmetro o endereço da imagem que você criou.

//arquivo ClasseMeuCanvas.java
import java.io.*;
import javax.microedition.lcdui.*;

public class ClasseMeuCanvas extends Canvas {
    Image minhaImagem;

    ClasseMeuCanvas throws Exception {
        minhaImagem = minhaImagem.createImage("/Minha Imagem.png");
    }
    public void paint(Graphics meuGrafico){
    }
}

Agora dentro do método paint() vamos botar a nossa imagem para ser exibida, utilizando o método drawImage() da classe Graphics, como parâmetro ele irá receber 4 atributos: o 1ª será o nome da variável da classe Image, o 2º será o pixel x de onde vai ser desenhado, o 3º será o pixel y de onde vai ser desenhado, o 4º será a "raiz" do objeto, ou seja, onde será a referência dos pixels x e y.

//arquivo ClasseMeuCanvas.java
import java.io.*;
import javax.microedition.lcdui.*;

public class ClasseMeuCanvas extends Canvas {
    Image minhaImagem;

    ClasseMeuCanvas throws Exception {
        minhaImagem = minhaImagem.createImage("/Minha Imagem.png");
    }
    public void paint(Graphics meuGrafico){
        meuGrafico.drawImage(minhaImagem, 30, 40, Graphics.LEFT|Graphics.TOP);
    }
}

Criando uma atualização de tela

Vimos como colocar objetos na tela através de um comando, agora vamos ver como se cria uma atualização de tela, para isso dentro do método paint() iremos usar o método repaint() que irá funcionar como um "retornador" para o método paint() ser executado novamente. Para isso vamos primeiro criar uma variável inteira i na ClasseMeuCanvas e vamos inicia-la com o valor 0.

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;

public class ClasseMeuCanvas extends Canvas {
    int i=0;
    public void paint(Graphics meuGrafico){
    }
}

Agora vamos desenhar um simples retângulo na tela, vamos usar como os primeiros atributos a variável i que criamos (que no caso vale 0).

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;

public class ClasseMeuCanvas extends Canvas {
    int i=0;
    public void paint(Graphics meuGrafico){
        meuGrafico.drawRect(i, i, 100, 100);
    }
}

Vamos agora dar um incremento no i, para sempre que se retornar ao paint() seu valor ser acrescido de +1.

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;

public class ClasseMeuCanvas extends Canvas {
    int i=0;
    public void paint(Graphics meuGrafico){
        meuGrafico.drawRect(i, i, 100, 100);
        i++;
    }
}

Vamos agora finalmente aplicar o método repaint() dentro do método paint(), e ver a movimentação do nosso retângulo na tela. Vamos mostrar abaixo o código completo.

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;

public class ClasseMeuCanvas extends Canvas {
    int i=0;
    public void paint(Graphics meuGrafico){
        meuGrafico.drawRect(i, i, 100, 100);
        i++;
        repaint();
    }
}

Comandos

Vamos entrar agora na parte de entrada de comandos através das teclas do celular, primeiramente a classe Canvas tem 3 métodos pré-definidos para isso, são o keyPressed() para quando se aperta a tecla do celular, keyRepeated() para quando se segura a tecla do celular e keyReleased() para quando se solta a tecla do celular.

Primeiramente para usá-lo vamos fazer a chamada do método fora do médodo paint(), o método deverá ser do tipo protected.

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;

public class ClasseMeuCanvas extends Canvas {
    protected void keyPressed(int getTecla){
    }

    public void paint(Graphics meuGrafico){
        repaint();
    }
}

Agora vamos definir uma ação para o caso de o usuário apertar a tecla que queremos, no caso vamos escolher a tecla 1 do celular, vamos colocar um if dentro do método keyPressed()'. Você pode comparar com as constantes KEY_NUM1, KEY_NUM2, ..., KEY_STAR, KEY_POUND.

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;

public class ClasseMeuCanvas extends Canvas {
    protected void keyPressed(int getTecla){
        if (getTecla == KEY_NUM1);
    }

    public void paint(Graphics meuGrafico){
        repaint();
    }
}

Agora vamos colocar uma ação para quando pressionarmos a tecla, nesse caso vamos exibir uma mensagem no console.

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;

public class ClasseMeuCanvas extends Canvas {
    protected void keyPressed(int getTecla){
        if (getTecla == KEY_NUM1){
            System.out.println("Pressionou tecla 1 do celular");
        }
    }

    public void paint(Graphics meuGrafico){
        repaint();
    }
}

Você pode usar o mesmo processo apenas trocando método keyPressed() por keyRepeated() ou keyReleased().

Comandos de jogo

Vimos como obter as teclas do teclado padrão do celular (apenas os números e as teclas * e #), agora vamos ver como pegar as teclas auxiliares.

Primeiramente vamos usar o mesmo método keyPressed(), keyRepeated() ou keyReleased() do módulo anterior.

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;

public class ClasseMeuCanvas extends Canvas {
    protected void keyPressed(int getTecla){
    }

    public void paint(Graphics meuGrafico){
        repaint();
    }
}

Agora as constantes das teclas auxiliares não podem ser pegas de forma direta, para isso vamos usar o método getKeyCode() e como parâmetro vamos entrar o código da tecla que queremos, nesse caso usamos a tecla FIRE que fica no meio das setas do celular.

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;

public class ClasseMeuCanvas extends Canvas {
    protected void keyPressed(int getTecla){
        if (getTecla == getKeyCode(FIRE));
    }

    public void paint(Graphics meuGrafico){
        repaint();
    }
}

Agora vamos colocar uma ação para quando pressionarmos a tecla, nesse caso vamos exibir uma mensagem no console.

public class ClasseMeuCanvas extends Canvas {
    protected void keyPressed(int getTecla){
        if (getTecla == getKeyCode(FIRE)){
            System.out.println("Pressionou tecla FIRE do celular");
        }
    }

    public void paint(Graphics meuGrafico){
        repaint();
    }
}

CommandListener

Agora entraremos na parte interativa onde o usuário pode interagir com as funções do celular através do teclado ou da caneta digital.

Estrutura básica do CommandListener

Antes de trabalharmos para receber comandos, na nossa classe Midlet precisamos implementar a classe CommandListener.

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class MinhaClasse extends MIDlet implements CommandListener{
    Display meuDisplay = Display.getDisplay(this);

    public void startApp() {
    }
    public void pauseApp() {
    }
    public void destroyApp(boolean unconditional) {
    }
}

Agora vamos inserir o método commandAction() que iremos usar diretamente para manipular as ações do teclado, esse método deverá sempre ter 2 parâmetros, o primeiro é o objeto da classe Command (que veremos logo após) e o outro é o objeto Displayable.

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class MinhaClasse extends MIDlet implements CommandListener{
    Display meuDisplay = Display.getDisplay(this);

    public void startApp() {
    }
    public void pauseApp() {
    }
    public void destroyApp(boolean unconditional) {
    }
    public void commandAction(Command pegarComando, Displayable pegarDisplay){
    }
}

Criando um comando

Para criar um comando primeiro precisamos intanciar uma variável do tipo Command.

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class MinhaClasse extends MIDlet implements CommandListener{
    Display meuDisplay = Display.getDisplay(this);

    Command meuComando;

    public void startApp() {
    }
    public void pauseApp() {
    }
    public void destroyApp(boolean unconditional) {
    }
    public void commandAction(Command pegarComando, Displayable pegarDisplay){
    }
}

Agora vamos criar o objeto Command, para isso vamos usar como parâmetro respectivamente: 1º o texto que será exibido na tela, 2º o tipo de comando e 3º a prioridade do comando.

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class MinhaClasse extends MIDlet implements CommandListener{
    Display meuDisplay = Display.getDisplay(this);

    Command meuComando = new Command("OK", Command.OK, 0);

    public void startApp() {
    }
    public void pauseApp() {
    }
    public void destroyApp(boolean unconditional) {
    }
    public void commandAction(Command pegarComando, Displayable pegarDisplay){
    }
}

Detectando a ação de um comando

Agora vamos para a parte prática, vamos detectar uma ação de comando pelo teclado do celular, já temos o objeto Command criado, agora vamos criar uma condição caso ele seja apertado.

Como vimos anteriormente é dentro do método commandAction() que fazemos os trabalhos com comandos, é através dos dos atributo do tipo Command que vamos fazer a comparação com o objeto Command externo que criamos, e vamos exibir uma mensagem no console.

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class MinhaClasse extends MIDlet implements CommandListener{
    Display meuDisplay = Display.getDisplay(this);

    Command meuComando = new Command("OK", Command.OK, 0);

    public void startApp() {
    }
    public void pauseApp() {
    }
    public void destroyApp(boolean unconditional) {
    }
    public void commandAction(Command pegarComando, Displayable pegarDisplay){
        if(pegarComando == meuComando){
            System.out.println("Pressionou o botão OK");
        }
    }
}

Agora calma, AINDA não vai acontecer nada quando apertarmos o botão, para isso precisamos criar a tela que irá "escutar" o comando que iremos colocar, podemos fazer a tela com qualquer objeto tipo Alert, TextBox, etc... no nosso caso vamos usar um simples Form.

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class MinhaClasse extends MIDlet implements CommandListener{
    Display meuDisplay = Display.getDisplay(this);

    Command meuComando = new Command("OK", Command.OK, 0);
    Form meuForm = new Form("Título do formulário");

    public void startApp() {
    }
    public void pauseApp() {
    }
    public void destroyApp(boolean unconditional) {
    }
    public void commandAction(Command pegarComando, Displayable pegarDisplay){
        if(pegarComando == meuComando){
            System.out.println("Pressionou o botão OK");
        }
    }
}

Agora dentro do método startApp() vamos adicionar o comando à tela do Form através do método addCommand().

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class MinhaClasse extends MIDlet implements CommandListener{
    Display meuDisplay = Display.getDisplay(this);

    Command meuComando = new Command("OK", Command.OK, 0);
    Form meuForm = new Form("Título do formulário");

    public void startApp() {
        meuForm.addCommand(meuComando);
    }
    public void pauseApp() {
    }
    public void destroyApp(boolean unconditional) {
    }
    public void commandAction(Command pegarComando, Displayable pegarDisplay){
        if(pegarComando == meuComando){
            System.out.println("Pressionou o botão OK");
        }
    }
}

Agora vamos adicionar o "escutador" no Form, para detectar se pressionamos ou não algum botão.

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class MinhaClasse extends MIDlet implements CommandListener{
    Display meuDisplay = Display.getDisplay(this);

    Command meuComando = new Command("OK", Command.OK, 0);
    Form meuForm = new Form("Título do formulário");

    public void startApp() {
        meuForm.addCommand(meuComando);
        meuForm.setCommandListener(this);
    }
    public void pauseApp() {
    }
    public void destroyApp(boolean unconditional) {
    }
    public void commandAction(Command pegarComando, Displayable pegarDisplay){
        if(pegarComando == meuComando){
            System.out.println("Pressionou o botão OK");
        }
    }
}

Por fim, colocamos normalmente o método setCurrent() da classe Display.

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class MinhaClasse extends MIDlet implements CommandListener{
    Display meuDisplay = Display.getDisplay(this);

    Command meuComando = new Command("OK", Command.OK, 0);
    Form meuForm = new Form("Título do formulário");

    public void startApp() {
        meuForm.addCommand(meuComando);
        meuForm.setCommandListener(this);
        meuDisplay.setCurrent(meuForm);
    }
    public void pauseApp() {
    }
    public void destroyApp(boolean unconditional) {
    }
    public void commandAction(Command pegarComando, Displayable pegarDisplay){
        if(pegarComando == meuComando){
            System.out.println("Pressionou o botão OK");
        }
    }
}

Form

Vamos agora aprender a fazer Forms (formulários), são dentro das forms que podemos inserir vários ítens de uma aplicação.

Inserindo um simples Form

Vamos ver como inserir um simples form numa aplicação, primeiro criamos o objeto Form.

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class MinhaClasse extends MIDlet {
    Display meuDisplay = Display.getDisplay(this);
    Form meuForm;

    public void startApp() {
    }
    public void pauseApp() {
    }
    public void destroyApp(boolean unconditional) {
    }
}

Agora vamos inicializar o formulário com o construtor, como parâmetro vamos colocar a String que será exibida na tela.

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class MinhaClasse extends MIDlet {
    Display meuDisplay = Display.getDisplay(this);
    Form meuForm = new Form("Título do formulário");

    public void startApp() {
    }
    public void pauseApp() {
    }
    public void destroyApp(boolean unconditional) {
    }
}

Agora vamos usar o método setCurrent() da classe Display entrando o nosso formulário como parâmetro para exibir o formulário na tela.

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class MinhaClasse extends MIDlet {
    Display meuDisplay = Display.getDisplay(this);
    Form meuForm = new Form("Título do formulário");

    public void startApp() {
        meuDisplay.setCurrent(meuForm);
    }
    public void pauseApp() {
    }
    public void destroyApp(boolean unconditional) {
    }
}

Inserindo ítens no Form

Como vimos, objetos Form podem conter vários ítens, aqui veremos que o construtor do Form pode conter outros parâmetros, vejamos agora cada um deles.

ChoiceGroup

CustomItem

DateField

Gauge

ImageItem

Spacer

StringItem

TextField

GameCanvas

O Canvas foi uma classe criada para o tratamentos de eventos de baixo nível, que durande o Midp1.0 foi muito usada na produção de jogos, a partir da versão Midp2.0, o J2ME apresentou uma nova classe, a GameCanvas com ações mais voltadas para a manipulação de jogos.

Iniciando um GameCanvas

Primeiramente vamos importar o pacote que contém a classe GameCanvas.

 import javax.microedition.lcdui.game.*;

Agora vamos criar a classe MeuGameCanvas, extendendo a classe GameCanvas.

 import javax.microedition.lcdui.game.*;

 public class MeuGameCanvas extends GameCanvas{
 }

Uma classe que extende o GameCanvas precisa obrigatoriamente de um construtor.

 import javax.microedition.lcdui.game.*;

 public class MeuGameCanvas extends GameCanvas{
     public MeuGameCanvas(){
     }
 }

Agora precisamos obrigatoriamente instanciar a classe superior GameCanvas dentro do construtor, usaremos o argumento true (se quisermos herdar os métodos da classe Canvas) ou false (se quisermos usar apenas os métodos da classe GameCanvas.

 import javax.microedition.lcdui.game.*;

 public class MeuGameCanvas extends GameCanvas {
     public MeuGameCanvas(){
         super(false);
     }
 }

Utilizando Canvas no GameCanvas

Do mesmo modo que a classe Canvas, na classe GameCanvas podemos usar o método paint() (que na GameCanvas é public) para exibir algo na tela. Vamos primeiramente inserir o pacote que contém a classe Canvas.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas {
     public MeuGameCanvas(){
         super(false);
     }

     public void paint(Graphics meuGrafico){
     }
 }

Agora vamos criar o método paint().

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas {
     public MeuGameCanvas(){
         super(false);
     }

     public void paint(Graphics meuGrafico){
     }
 }

Agora vamos desenhar um retângulo na tela.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas {
     public MeuGameCanvas(){
         super(false);
     }

     public void paint(Graphics meuGrafico){
         meuGrafico.drawRect(10, 20, 100, 200);
     }
 }

Também podemos implementar outros métodos da classe Canvas como o keyPressed() (como public).

Estrutura básica do GameCanvas

Vimos que podemos fazer tudo que fazíamos no Canvas dentro do GameCanvas, mas vamos ver agora que o GameCanvas não trabalha somente "reinventando a roda", ele possui um tratamento diferente que se assemelha mais as várias APIs de criação de jogos que existem por ai, não vamos trabalhar com um método padrão, e sim com loops que irão fixar a tela, até quando uma condição faça com que o loop pare.

Bom, primeiramente agora que não temos mais o método paint() que era inicializado automaticamente, vamos agora usar outro método que também é chamado automaticamente, ele está dentro da interface Runnable, vamos implementar na classe.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     public MeuGameCanvas(){
         super(false);
     }
 }

Agora devemos obrigatoriamente incluir dentro da nossa classe o método run() da interface Runnable que é o método que é chamado automaticamente, será dentro dele que iremos incluir todas as ações da classe.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     public MeuGameCanvas(){
         super(false);
     }
     public void run(){
     }
 }

Agora vamos instanciar um objeto da classe Thread, ele será o controlador que irá iniciar a nossa classe.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;

     public MeuGameCanvas(){
         super(false);
     }
     public void run(){
     }
 }

Devemos agora iniciar o objeto thread dentro do construtor da classe, como parâmetro vamos usar o this da classe GameCanvas.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
     }
     public void run(){
     }
 }

Já temos tudo pronto, agora por último vamos iniciar a o objeto Thread que criamos utilizando o método start() dentro do construtor.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
     }
 }

Exibindo algo no GameCanvas

Agora com a estrutura básica do nosso GameCanvas pronta, precisamos criar um objeto do tipo Graphics dentro da nossa classe GameCanvas.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
     }
 }

Agora dentro criaremos o loop principal dentro do método run(), primeiramente vamos criar uma variavel booleana, para criar a condição do jogo.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         boolean fimDeJogo = false;
     }
 }

Agora vamos criar o loop com um comando while que irá comparar a variavel booleana que criamos.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         boolean fimDeJogo = false;
         while(fimDeJogo == false){
         }
     }
 }

Por fim dentro do loop vamos chamar o método flushGraphics() que irá desenhar o gráfico na tela do celular.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         boolean fimDeJogo = false;
         while(fimDeJogo == false){
             flushGraphics();
         }
     }
 }

Agora como exemplo vamos exibir um retângulo na tela através do objeto do tipo Graphics.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         boolean fimDeJogo = false;
         while(fimDeJogo == false){
             meuGrafico.drawRect(10, 20, 100, 200);
             flushGraphics();
         }
     }
 }

Controlando a velocidade do aplicativo

Agora que fizemos a exibição precisamos controlar a velocidade de atualização do loop, isso porque do jeito que está o aplicativo irá rodar mais rápido em celulares com melhor hardware e mais lentos em celulares com pior hardware.

Para isso primeiramente precisamos criar um try-catch-finally dentro do loop principal.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         boolean fimDeJogo = false;
         while(fimDeJogo == false){
             try{
             }catch (Exception minhaExcessao){
                 minhaExcessao.printStackTrace();
             }finally{
             }
         }
     }
 }

Agora, como devemos sempre pintar a tela a cada loop colocamos o flushGraphics() dentro do finally.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         boolean fimDeJogo = false;
         while(fimDeJogo == false){
             try{
             }catch (Exception minhaExcessao){
                 minhaExcessao.printStackTrace();
             }finally{
                 flushGraphics();
             }
         }
     }
 }

Agora dentro do try vamos utilizar o método sleep() da classe Thread e entrar como parâmetro o tempo em milisegundos que a aplicação deve esperar para chamar o próximo loop, nesse caso iremos esperar 50 milisegundos (o que dá 20 quadros por segundo) que é mais ou menos a taxa de atualização da tela da maioria dos celulares.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         boolean fimDeJogo = false;
         while(fimDeJogo == false){
             try{
                 meuThread.sleep(50);
             }catch (Exception minhaExcessao){
                 minhaExcessao.printStackTrace();
             }finally{
                 flushGraphics();
             }
         }
     }
 }

Agora por último colocaremos um simples retângulo para andar na tela, para isso criaremos uma variável int auxiliar que irá encrementar-se a cada loop, e depois usaremos essa variável em um parâmetro do método drawRect().

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         int auxiliar = 0;
         boolean fimDeJogo = false;
         while(fimDeJogo == false){
             try{
                 meuGrafico.drawRect(auxiliar, 0, 10, 20);
                 meuThread.sleep(50);
             }catch (Exception minhaExcessao){
                 minhaExcessao.printStackTrace();
             }finally{
                 auxiliar++;
                 flushGraphics();
             }
         }
     }
 }

Você pode mudar a taxa de atualização na tela (método sleep()) e verá que o retângulo irá se mover com diferentes velocidades.

Controles no GameCanvas

No Canvas tratávamos separadamente a parte dos comandos e a parte dos gráfico, agora no GameCanvas podemos tratar dessas coisas tudo no mesmo loop, vamos ver agora que essa parte será tratada de uma forma bem diferente e muito mais simples.

Primeiramente dentro do run() vamos criar uma variável que tem que ser do tipo int que irá receber os controles.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         boolean fimDeJogo = false;
         int tecla;

         while(fimDeJogo == false){
             try{
                 meuGrafico.drawRect(10, 20, 100, 200);
             }catch(Exception minhaExcessao){
                 minhaExcessao.printStackTrace();
             }finally{
                 flushGraphics();
             }
         }
     }
 }

Agora dentro do loop principal vamos checar se alguma tecla foi pressionada através do método getKeyStates().

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         boolean fimDeJogo = false;
         int tecla;

         while(fimDeJogo == false){
             try{
                 tecla = getKeyStates();
                 meuGrafico.drawRect(10, 20, 100, 200);
             }catch(Exception minhaExcessao){
                 minhaExcessao.printStackTrace();
             }finally{
                 flushGraphics();
             }
         }
     }
 }

Agora vamos criar uma condição caso uma tecla específica seja apertada, nesse caso vamos usar a tecla FIRE e desenhar outro retângulo na tela caso ela seja apertada, note que agora vamos usar a constante FIRE_PRESSED.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         boolean fimDeJogo = false;
         int tecla;

         while(fimDeJogo == false){
             try{
                 tecla = getKeyStates();
                 if(tecla == FIRE_PRESSED){
                     meuGrafico.drawRect(20, 40, 80, 100);
                 }

                 meuGrafico.drawRect(10, 20, 100, 200);
             }catch(Exception minhaExcessao){
                 minhaExcessao.printStackTrace();
             }finally{
                 flushGraphics();
             }
         }
     }
 }

Imagens no GameCanvas

Vamos agora ver como carregar uma imagem no GameCanvas, isso pode se aplicar ao carregamento de outros arquivos também.

Primeiramente dentro do método run() vamos colocar um try-catch.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         try{
         }catch(Exception minhaExcessao){
             minhaExcessao.printStackTrace();
         }

         boolean fimDeJogo = false;
         while(fimDeJogo == false){
             try{
                 meuThread.sleep(50);
             }catch(Exception minhaExcessao){
                 minhaExcessao.printStackTrace();
             }finally{
                 flushGraphics();
             }
         }
     }
 }

Agora dentro do vamos instanciar o objeto Image na classe MeuGameCanvas.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();
     Image minhaImagem;

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         try{
             meuThread.sleep(50);
         }catch(Exception ex){
             ex.printStackTrace();
         }

         boolean fimDeJogo = false;
         while(fimDeJogo == false){
             try{
             }catch(Exception minhaExcessao){
                 minhaExcessao.printStackTrace();
             }finally{
                 flushGraphics();
             }
         }
     }
 }

Depois vamos iniciar o objeto Image dentro do try no método run().

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();
     Image minhaImagem;

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         try{
             minhaImagem = minhaImagem.createImage("/Minha Imagem.png");
         }catch(Exception ex){
             ex.printStackTrace();
         }

         boolean fimDeJogo = false;
         while(fimDeJogo == false){
             try{
                 meuThread.sleep(50);
             }catch(Exception minhaExcessao){
                 minhaExcessao.printStackTrace();
             }finally{
                 flushGraphics();
             }
         }
     }
 }

Agora normalmente dentro do loop do jogo colocamos a imagem para ser exibida.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();
     Image minhaImagem;

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         try{
             minhaImagem = minhaImagem.createImage("/Minha Imagem.png");
         }catch(Exception ex){
             ex.printStackTrace();
         }

         boolean fimDeJogo = false;
         while(fimDeJogo == false){
             try{
                 meuGrafico.drawImage(minhaImagem, 30, 40, Graphics.LEFT|Graphics.TOP);
                 meuThread.sleep(50);
             }catch(Exception minhaExcessao){
                 minhaExcessao.printStackTrace();
             }finally{
                 flushGraphics();
             }
         }
     }
 }

Instalação

  1. Para começar a desenvolver aplicativos em J2ME você primeiro precisa ter instalado no computador o J2SE, para baixa-lo clique aqui.
  2. Após instalado o J2SE você irá baixar o J2ME clicando aqui.
  3. Após instalado o J2SE e o J2ME você já pode começar a programar suas applets.
  4. Para instalar a IDE NetBeans com o Mobility Pack clique aqui.
  5. Para instalar a IDE Eclipse com a ferramenta Pulsar para desenvolvimento para celular clique aqui.

LayerManager

Já vimos como mostrar gráficos na nossa tela, agora iremos ver algo mais relacionado ao desenvolvimento de jogos em 2D utilizando as classes TiledLayer, Sprite e LayerManager.

Tiles podem ser compreendidos como blocos usados para a construção de cenários estáticos em jogos 2D, a técnica de construção usando Tiles é praticamente a mesma em qualquer plataforma, cria-se um objeto e utiliza-se um vetor para posicionar os Tiles no cenário. Sprites são os seres dinâmicos do jogo como personagens, inimigos, objetos móveis, etc. No J2ME temos a classe LayerManager que serve para controlar e mostrar o mundo do jogo construído através de Tiles e Sprites.

TiledLayer

Vamos começar utilizando a mesma estrutura do GameCanvas.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         boolean fimDeJogo = false;
         while(fimDeJogo == false){
             try{
                 meuThread.sleep(50);
             }(catch Exception minhaEscessao){
                 minhaExcessao.printStackTrance();
             }finally{
                 flushGraphics();
             }
         }
     }
 }

Primeiramente precisamos carregar a imagem onde estão desenhados os tiles, para isso vamos instanciar e criar o objeto do tipo Image como vimos anteriormente.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     Image minhaImagem;

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         try{
             minhaImagem = minhaImagem.createImage("/Minha Imagem.png");
         }catch(Exception ex){
             ex.printStackTrance();
         }
         boolean fimDeJogo = false;
         while(fimDeJogo == false){
             try{
                 meuThread.sleep(50);
             }(catch Exception minhaEscessao){
                 minhaExcessao.printStackTrance();
             }finally{
                 flushGraphics();
             }
         }
     }
 }

Agora vamos instanciar a variável do tipo TiledLayer.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     Image minhaImagem;
     TiledLayer meuTiledLayer;

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         try{
             minhaImagem = minhaImagem.createImage("/Minha Imagem.png");
         }catch(Exception ex){
             ex.printStackTrance();
         }
         boolean fimDeJogo = false;
         while(fimDeJogo == false){
             try{
                 meuThread.sleep(50);
             }(catch Exception minhaEscessao){
                 minhaExcessao.printStackTrance();
             }finally{
                 flushGraphics();
             }
         }
     }
 }

Agora dentro do método run() vamos criar o objeto TiledLayer, vamos entrar com 4 parâmetros: O primeiro é a quantidade de linhas que o cenário vai ter. O segundo é q quantidade de colunas que o cenário vai ter. O terceiro é o objeto Image carregado. O quarto é a largura em pixels de cada tile. O quinto é a altura em pixels de cada tile.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     Image minhaImagem;
     TiledLayer meuTiledLayer;

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         try{
             minhaImagem = minhaImagem.createImage("/Minha Imagem.png");
             meuTiledLayer = new TiledLayer(5, 5, minhaImagem, 16, 16);
         }catch(Exception ex){
             ex.printStackTrance();
         }
         boolean fimDeJogo = false;
         while(fimDeJogo == false){
             try{
                 meuThread.sleep(50);
             }(catch Exception minhaEscessao){
                 minhaExcessao.printStackTrance();
             }finally{
                 flushGraphics();
             }
         }
     }
 }

Agora para vamos criar o vetor para desenharmos a grade de tiles, para isso devemos criar um vetor do tipo int[] e colocar o valor correspondente ao tile, lembre-se que no nosso exemplo usamos uma grade de no máximo 5x5 tiles.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     Image minhaImagem;
     TiledLayer meuTiledLayer;

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         try{
             minhaImagem = minhaImagem.createImage("/Minha Imagem.png");
             meuTiledLayer = new TiledLayer(5, 5, minhaImagem, 16, 16);
             int grade[] = { 2, 1, 1, 1, 3,
                             1, 0, 0, 0, 1,
                             1, 0, 1, 0, 1,
                             1, 0, 0, 0, 1,
                             4, 1, 1, 1, 5 };
         }catch(Exception ex){
             ex.printStackTrance();
         }
         boolean fimDeJogo = false;
         while(fimDeJogo == false){
             try{
                 meuThread.sleep(50);
             }(catch Exception minhaEscessao){
                 minhaExcessao.printStackTrance();
             }finally{
                 flushGraphics();
             }
         }
     }
 }

Agora com o vetor da grade já criado, devemos inseri-lo dentro do objeto TiledLayer, a inserção é feita através do método setCell() onde inserimos cada célula individualmente, para isso vemos criar um laço for criando uma variável de zero até menor que grade.length.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     Image minhaImagem;
     TiledLayer meuTiledLayer;

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         try{
             minhaImagem = minhaImagem.createImage("/Minha Imagem.png");
             meuTiledLayer = new TiledLayer(5, 5, minhaImagem, 16, 16);
             int grade[] = { 2, 1, 1, 1, 3,
                             1, 0, 0, 0, 1,
                             1, 0, 1, 0, 1,
                             1, 0, 0, 0, 1,
                             4, 1, 1, 1, 5 };
             for(int i=0; i<grade.length; i++){
             }
         }catch(Exception ex){
             ex.printStackTrance();
         }
         boolean fimDeJogo = false;
         while(fimDeJogo == false){
             try{
                 meuThread.sleep(50);
             }(catch Exception minhaEscessao){
                 minhaExcessao.printStackTrance();
             }finally{
                 flushGraphics();
             }
         }
     }
 }

Agora dentro do laço for vamos finalmente usar o método setCell() da classe TiledLayer utilizando os seguintes atributos: Primeiro a linha em que está sendo inserido. Segundo a coluna em que está sendo inserido. Terceiro o valor do tile (a célula do vetor grade[]).

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     Image minhaImagem;
     TiledLayer meuTiledLayer;

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         try{
             minhaImagem = minhaImagem.createImage("/Minha Imagem.png");
             meuTiledLayer = new TiledLayer(5, 5, minhaImagem, 16, 16);
             int grade[] = { 2, 1, 1, 1, 3,
                             1, 0, 0, 0, 1,
                             1, 0, 1, 0, 1,
                             1, 0, 0, 0, 1,
                             4, 1, 1, 1, 5 };
             for(int i=0; i<grade.length; i++){
                 meuTiledLayer.setCell(i%6, i/6, grade[i]);
             }
         }catch(Exception ex){
             ex.printStackTrance();
         }
         boolean fimDeJogo = false;
         while(fimDeJogo == false){
             try{
                 meuThread.sleep(50);
             }(catch Exception minhaEscessao){
                 minhaExcessao.printStackTrance();
             }finally{
                 flushGraphics();
             }
         }
     }
 }

Sprite

Sprites são imagens com animação geralmente usados como personagens, inimigos ou objetos móveis, vamos ver como implementa-los no J2ME. Inicialmente vamos carregar a imagem onde está desenhado o Sprite, para isso vamos instanciar e criar um objeto do tipo Image como vimos anteriomente.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     Image minhaImagem;

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         try{
             minhaImagem = minhaImagem.createImage("/Minha Imagem.png");
         }catch(Exception ex){
             ex.printStackTrance();
         }
         boolean fimDeJogo = false;
         while(fimDeJogo == false){
             try{
                 meuThread.sleep(50);
             }(catch Exception minhaEscessao){
                 minhaExcessao.printStackTrance();
             }finally{
                 flushGraphics();
             }
         }
     }
 }

Agora vamos instanciar a variável do tipo Sprite.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     Image minhaImagem;
     Sprite meuSprite;

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         try{
             minhaImagem = minhaImagem.createImage("/Minha Imagem.png");
         }catch(Exception ex){
             ex.printStackTrance();
         }
         boolean fimDeJogo = false;
         while(fimDeJogo == false){
             try{
                 meuThread.sleep(50);
             }(catch Exception minhaEscessao){
                 minhaExcessao.printStackTrance();
             }finally{
                 flushGraphics();
             }
         }
     }
 }

Agora dentro do método run() vamos criar o objeto do tipo Sprite, vamos entrar 3 parâmetros: Primeiro o objeto do tipo Image. Segundo a largura em pixels de cada cena. Terceiro a altura em pixels de cada cena.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     Image minhaImagem;

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         try{
             minhaImagem = minhaImagem.createImage("/Minha Imagem.png");
             meuSprite = new Sprite(minhaImagem, 32, 32);
         }catch(Exception ex){
             ex.printStackTrance();
         }
         boolean fimDeJogo = false;
         while(fimDeJogo == false){
             try{
                 meuThread.sleep(50);
             }(catch Exception minhaEscessao){
                 minhaExcessao.printStackTrance();
             }finally{
                 flushGraphics();
             }
         }
     }
 }

LayerManager

Vimos como carregar e criar Tiles e Sprites, agora vamos ver como coloca-los para serem exibidos na tela, para isso iremos ver como usar o LayerManager. Para começar vamos instanciar e inicializar os objetos do tipo TiledLayer e Sprite vistos anteriormente.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     Image minhaImagemTile;
     TiledLayer meuTiledLayer;
     Image minhaImagemSprite;
     Sprite meuSprite;

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         try{
             minhaImagemTile = minhaImagemTile.createImage("/Minha Imagem tile.png");
             meuTiledLayer = new TiledLayer(5, 5, minhaImagemTile, 16, 16);
             int grade[] = { 2, 1, 1, 1, 3,
                             1, 0, 0, 0, 1,
                             1, 0, 1, 0, 1,
                             1, 0, 0, 0, 1,
                             4, 1, 1, 1, 5 };
             for(int i=0; i<grade.length; i++){
                 meuTiledLayer.setCell(i%6, i/6, grade[i]);
             }
             minhaImagemSprite = minhaImagemSprite.createImage("/Minha Imagem sprite.png");
             meuSprite = new Sprite(minhaImagemSprite, 32, 32);
         }catch(Exception ex){
             ex.printStackTrance();
         }
         boolean fimDeJogo = false;
         while(fimDeJogo == false){
             try{
                 meuThread.sleep(50);
             }(catch Exception minhaEscessao){
                 minhaExcessao.printStackTrance();
             }finally{
                 flushGraphics();
             }
         }
     }
 }

Agora para começarmos a controlar a exibição de Tiles e Sprites primeiramente devemos instanciar uma variável do tipo LayerManager.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     Image minhaImagemTile;
     TiledLayer meuTiledLayer;
     Image minhaImagemSprite;
     Sprite meuSprite;
     LayerManager meuLayerManager;

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         try{
             minhaImagemTile = minhaImagemTile.createImage("/Minha Imagem tile.png");
             meuTiledLayer = new TiledLayer(5, 5, minhaImagemTile, 16, 16);
             int grade[] = { 2, 1, 1, 1, 3,
                             1, 0, 0, 0, 1,
                             1, 0, 1, 0, 1,
                             1, 0, 0, 0, 1,
                             4, 1, 1, 1, 5 };
             for(int i=0; i<grade.length; i++){
                 meuTiledLayer.setCell(i%6, i/6, grade[i]);
             }
             minhaImagemSprite = minhaImagemSprite.createImage("/Minha Imagem sprite.png");
             meuSprite = new Sprite(minhaImagemSprite, 32, 32);
         }catch(Exception ex){
             ex.printStackTrance();
         }
         boolean fimDeJogo = false;
         while(fimDeJogo == false){
             try{
                 meuThread.sleep(50);
             }(catch Exception minhaEscessao){
                 minhaExcessao.printStackTrance();
             }finally{
                 flushGraphics();
             }
         }
     }
 }

Agora dentro do run() vamos criar o objeto do tipo LayerManager

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     Image minhaImagemTile;
     TiledLayer meuTiledLayer;
     Image minhaImagemSprite;
     Sprite meuSprite;
     LayerManager meuLayerManager;

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         try{
             minhaImagemTile = minhaImagemTile.createImage("/Minha Imagem tile.png");
             meuTiledLayer = new TiledLayer(5, 5, minhaImagemTile, 16, 16);
             int grade[] = { 2, 1, 1, 1, 3,
                             1, 0, 0, 0, 1,
                             1, 0, 1, 0, 1,
                             1, 0, 0, 0, 1,
                             4, 1, 1, 1, 5 };
             for(int i=0; i<grade.length; i++){
                 meuTiledLayer.setCell(i%6, i/6, grade[i]);
             }
             minhaImagemSprite = minhaImagemSprite.createImage("/Minha Imagem sprite.png");
             meuSprite = new Sprite(minhaImagemSprite, 32, 32);
             meuLayerManager = new LayerManager();
         }catch(Exception ex){
             ex.printStackTrance();
         }
         boolean fimDeJogo = false;
         while(fimDeJogo == false){
             try{
                 meuThread.sleep(50);
             }(catch Exception minhaEscessao){
                 minhaExcessao.printStackTrance();
             }finally{
                 flushGraphics();
             }
         }
     }
 }

Agora vamos colocar organizar os objetos do tipo Sprite e TiledLayer para serem exibidos, para isso vamos usar o método append() da classe LayerManager, note que quando se pintar a tela a ordem dos elementos inseridos irá influenciar o que será exibido em cima do outro, sempre o primeiro objeto colocado no append() será o que ficará sempre visível, nesse exemplo vamos insrir na ordem, meuSprite -> meuTile.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     Image minhaImagemTile;
     TiledLayer meuTiledLayer;
     Image minhaImagemSprite;
     Sprite meuSprite;
     LayerManager meuLayerManager;

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         try{
             minhaImagemTile = minhaImagemTile.createImage("/Minha Imagem tile.png");
             meuTiledLayer = new TiledLayer(5, 5, minhaImagemTile, 16, 16);
             int grade[] = { 2, 1, 1, 1, 3,
                             1, 0, 0, 0, 1,
                             1, 0, 1, 0, 1,
                             1, 0, 0, 0, 1,
                             4, 1, 1, 1, 5 };
             for(int i=0; i<grade.length; i++){
                 meuTiledLayer.setCell(i%6, i/6, grade[i]);
             }
             minhaImagemSprite = minhaImagemSprite.createImage("/Minha Imagem sprite.png");
             meuSprite = new Sprite(minhaImagemSprite, 32, 32);
             meuLayerManager = new LayerManager();
             meuLayerManager.append(meuSprite);
             meuLayerManager.append(meuTile);
         }catch(Exception ex){
             ex.printStackTrance();
         }
         boolean fimDeJogo = false;
         while(fimDeJogo == false){
             try{
                 meuThread.sleep(50);
             }(catch Exception minhaEscessao){
                 minhaExcessao.printStackTrance();
             }finally{
                 flushGraphics();
             }
         }
     }
 }

Agora colocaremos a cena para ser exibida na tela, dentro do loop principal vamos usar o método paint() da classe LayerManager e entrar como parâmetros: 1º o objeto do tipo Graphics. 2º o pixel x de onde a cena começará a ser exibida. 3º o pixel y de onde a cena começará a ser exibida.

 import javax.microedition.lcdui.game.*;
 import javax.microedition.lcdui.*;

 public class MeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();

     Image minhaImagemTile;
     TiledLayer meuTiledLayer;
     Image minhaImagemSprite;
     Sprite meuSprite;
     LayerManager meuLayerManager;

     public MeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         try{
             minhaImagemTile = minhaImagemTile.createImage("/Minha Imagem tile.png");
             meuTiledLayer = new TiledLayer(5, 5, minhaImagemTile, 16, 16);
             int grade[] = { 2, 1, 1, 1, 3,
                             1, 0, 0, 0, 1,
                             1, 0, 1, 0, 1,
                             1, 0, 0, 0, 1,
                             4, 1, 1, 1, 5 };
             for(int i=0; i<grade.length; i++){
                 meuTiledLayer.setCell(i%6, i/6, grade[i]);
             }
             minhaImagemSprite = minhaImagemSprite.createImage("/Minha Imagem sprite.png");
             meuSprite = new Sprite(minhaImagemSprite, 32, 32);
             meuLayerManager = new LayerManager();
             meuLayerManager.append(meuSprite);
             meuLayerManager.append(meuTile);
         }catch(Exception ex){
             ex.printStackTrance();
         }
         boolean fimDeJogo = false;
         while(fimDeJogo == false){
             try{
                 meuLayerManager.paint(meuGrafico, 0, 0);
                 meuThread.sleep(50);
             }(catch Exception minhaEscessao){
                 minhaExcessao.printStackTrance();
             }finally{
                 flushGraphics();
             }
         }
     }
 }

Colisão

M3G

Vamos agora iniciar o estudo do pacote M3G, é esse pacote que trabalha com a parte de gráficos em 3D no J2ME, para um bom uso é necessário que se tenha um bom conhecimento no Canvas e no GameCanvas.

  1. No Canvas ==
  2. No GameCanvas ==
  3. Modificando objetos 3D ==
  4. Criando objetos primitivos ==
  5. Colisões ==

M3G/Colisões

Colisões podem parecer simples em 2D, mas são um pouco mais complicadas no mundo em 3D, vamos ver aqui como fazer colisões da câmera para as meshes do cenário.

Checando colisões

Vamos ver como checar colisões, primeiramente devemos criar um objeto do tipo RayIntersection, é ele que vai armazenar todos os dados da colisão.

import javax.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;
    Camera minhaCamera = new Camera();
    RayIntersection meuRayIntersection;

    public ClasseMeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
            meuMundo = (World) meuObjeto3D[0];
            minhaCamera = meuMundo.getActiveCamera();
        }catch(Exception minhaExcessao){
            minhaExcessao.printStackTrance();
        }

        boolean gameOver = false;
        while(gameOver == false){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                meuGrafico3D.render(meuMundo);
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrance)();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

Agora vamos criar 2 arrays de float, um irá pegar a posição X, Y, Z da câmera, o outro irá pegar a oriêntação da câmera. Essas variáveis devem ser obrigatoriamente iniciadas.

import javax.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;
    Camera minhaCamera = new Camera();
    RayIntersection meuRayIntersection;

    public ClasseMeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }

    public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
            meuMundo = (World) meuObjeto3D[0];
            minhaCamera = meuMundo.getActiveCamera();
        }catch(Exception minhaExcessao){
            minhaExcessao.printStackTrance();
        }

        float[] translacaoCamera = {0.0f, 0.0f, 0.0f}
        float[] orientacaoCamera = {0.0f, 0.0f, 0.0f, 0.0f}
        boolean gameOver = false;
        while(gameOver == false){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                meuGrafico3D.render(meuMundo);
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrance)();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

Agora vamos criar uma variável booleana para checar se houve uma colisão, vamos coloca-la inicialmente como false.

import javax.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;
    Camera minhaCamera = new Camera();
    RayIntersection meuRayIntersection;

    public ClasseMeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
            meuMundo = (World) meuObjeto3D[0];
            minhaCamera = meuMundo.getActiveCamera();
        }catch(Exception minhaExcessao){
            minhaExcessao.printStackTrance();
        }

        float[] translacaoCamera = {0.0f, 0.0f, 0.0f}
        float[] orientacaoCamera = {0.0f, 0.0f, 0.0f, 0.0f}
        boolean colisao = false;
        boolean gameOver = false;
        while(gameOver == false){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                meuGrafico3D.render(meuMundo);
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrance)();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

Agora dentro do loop principal, vamos usar os métodos getTranslation() e getOrientation() para armazenar nas variáveis translacaoCamera e rotacaoCamera, os atributos da nossa câmera.

import javax.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;
    Camera minhaCamera = new Camera();
    RayIntersection meuRayIntersection;

    public ClasseMeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
            meuMundo = (World) meuObjeto3D[0];
            minhaCamera = meuMundo.getActiveCamera();
        }catch(Exception minhaExcessao){
            minhaExcessao.printStackTrance();
        }

        float[] translacaoCamera = {0.0f, 0.0f, 0.0f}
        float[] orientacaoCamera = {0.0f, 0.0f, 0.0f, 0.0f}
        boolean colisao = false;
        boolean gameOver = false;
        while(gameOver == false){
            try {
                meuGrafico3D.bindTarget(meuGrafico);

                minhaCamera.getTranslation(translacaoCamera);
                minhaCamera.getOrientation(orientacaoCamera);

                meuGrafico3D.render(meuMundo);
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrance)();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

Agora vamos testar a colisão através do método pick(), que terá como enrada os seguintes valores:

  1. escopo - sempre será -1
  2. posição X - a posição X da câmera que foi pega no getTranslation()
  3. posição Y - a posição Y da câmera que foi pega no getTranslation()
  4. posição Z - a posição Z da câmera que foi pega no getTranslation()
  5. orientação X - a orientação X da câmera que foi pega no getOrientation()
  6. orientação Y - a orientação Y da câmera que foi pega no getOrientation()
  7. orientação Z - a orientação Z da câmera que foi pega no getOrientation()
  8. RayIntersection - o objeto RayIntersection que criamos anteriormente

Esse método pick() irá retornar a condição true ou false para a nossa variável booleana colisao;

import javax.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;
    Camera minhaCamera = new Camera();
    RayIntersection meuRayIntersection;

    public ClasseMeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
            meuMundo = (World) meuObjeto3D[0];
            minhaCamera = meuMundo.getActiveCamera();
        }catch(Exception minhaExcessao){
            minhaExcessao.printStackTrance();
        }

        float[] translacaoCamera = {0.0f, 0.0f, 0.0f}
        float[] orientacaoCamera = {0.0f, 0.0f, 0.0f, 0.0f}
        boolean colisao = false;
        boolean gameOver = false;
        while(gameOver == false){
            try {
                meuGrafico3D.bindTarget(meuGrafico);

                minhaCamera.getTranslation(translacaoCamera);
                minhaCamera.getOrientation(orientacaoCamera);
                colisao = meuMundo.pick(-1,
                                        translacaoCamera[0],
                                        translacaoCamera[1],
                                        translacaoCamera[2],
                                        orientacaoCamera[1],
                                        orientacaoCamera[2],
                                        orientacaoCamera[3],
                                        meuRayIntersection);

                meuGrafico3D.render(meuMundo);
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrance)();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

Agora, vamos criar um 'if para caso a colisão seja verdadeira mostrar uma mensagem no console.

import javax.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;
    Camera minhaCamera = new Camera();
    RayIntersection meuRayIntersection;

    public ClasseMeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
            meuMundo = (World) meuObjeto3D[0];
            minhaCamera = meuMundo.getActiveCamera();
        }catch(Exception minhaExcessao){
            minhaExcessao.printStackTrance();
        }

        float[] translacaoCamera = {0.0f, 0.0f, 0.0f}
        float[] orientacaoCamera = {0.0f, 0.0f, 0.0f, 0.0f}
        boolean colisao = false;
        boolean gameOver = false;
        while(gameOver == false){
            try {
                meuGrafico3D.bindTarget(meuGrafico);

                minhaCamera.getTranslation(translacaoCamera);
                minhaCamera.getOrientation(orientacaoCamera);
                colisao = meuMundo.pick(-1,
                                        translacaoCamera[0],
                                        translacaoCamera[1],
                                        translacaoCamera[2],
                                        orientacaoCamera[1],
                                        orientacaoCamera[2],
                                        orientacaoCamera[3],
                                        meuRayIntersection);
                if (colisao == true){
                    System.out.println("Colisão verdadeira");
                }

                meuGrafico3D.render(meuMundo);
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrance)();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

M3G/Criando objetos primitivos

Além de poder carregar objetos externos você também pode criar objetos primitivos usando os recursos do próprio M3G.

Criando uma câmera

Apesar do arquivo .m3g ter a facilidade de se poder criar a própria câmera, ela pode apresentar alguns tipos de dificuldade em relação ao aspecto de tela de cada celular, que pode deixar o gráfico exibido no celular "esticado" tanto horizontalmente quanto verticalmente. Para resolver isso é recomendável criar uma própria câmera definindo os aspectos de cada celular.

Para fazer isso crie um arquivo .m3g em algum editor externo, mas lembre-se de NÃO colocar uma câmera no arquivo, já que essa nós vamos criar manualmente. Com o arquivo criado vamos carrega-lo normalmente como fizemos anteriomente, adicionar no objeto World, e renderiza-lo normalmente.

 import javax.io.*;
 import javax.microedition.lcdui.*;
 import javax.microedition.m3g.*;
 import javax.microedition.game.*;

 public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();
     Graphics3D meuGrafico3D = Graphics3D.getInstance();
     Object3D[] meuObjeto3D;
     World meuMundo;

     public ClasseMeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         try{
             meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
             meuMundo = (World) meuObjeto3D[0];
         }catch(Exception minhaExcessao){
             minhaExcessao.printStackTrance();
         }

         boolean gameOver = false;
         while(gameOver == false){
             try {
                 meuGrafico3D.bindTarget(meuGrafico);
                 meuGrafico3D.render(meuMundo);
                 meuThread.sleep(50);
             } catch (Exception minhaExcecao) {
                 minhaExcecao.printStackTrance)();
             } finally {
                 meuGrafico3D.releaseTarget();
                 flushGraphics();
             }
         }
     }
 }

Agora, como vamos manipular a câmera manualmente vamos criar um objeto do tipo Camera.

 import javax.io.*;
 import javax.microedition.lcdui.*;
 import javax.microedition.m3g.*;
 import javax.microedition.game.*;

 public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();
     Graphics3D meuGrafico3D = Graphics3D.getInstance();
     Object3D[] meuObjeto3D;
     World meuMundo;
     Camera minhaCamera;

     public ClasseMeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         try{
             meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
             meuMundo = (World) meuObjeto3D[0];
         }catch(Exception minhaExcessao){
             minhaExcessao.printStackTrance();
         }

         boolean gameOver = false;
         while(gameOver == false){
             try {
                 meuGrafico3D.bindTarget(meuGrafico);
                 meuGrafico3D.render(meuMundo);
                 meuThread.sleep(50);
             } catch (Exception minhaExcecao) {
                 minhaExcecao.printStackTrance)();
             } finally {
                 meuGrafico3D.releaseTarget();
                 flushGraphics();
             }
         }
     }
 }

Agora dentro do construtor vamos inicializar a câmera.

 import javax.io.*;
 import javax.microedition.lcdui.*;
 import javax.microedition.m3g.*;
 import javax.microedition.game.*;

 public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();
     Graphics3D meuGrafico3D = Graphics3D.getInstance();
     Object3D[] meuObjeto3D;
     World meuMundo;
     Camera minhaCamera;

     public ClasseMeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         try{
             meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
             meuMundo = (World) meuObjeto3D[0];
             minhaCamera = new Camera();
         }catch(Exception minhaExcessao){
             minhaExcessao.printStackTrance();
         }

         boolean gameOver = false;
         while(gameOver == false){
             try {
                 meuGrafico3D.bindTarget(meuGrafico);
                 meuGrafico3D.render(meuMundo);
                 meuThread.sleep(50);
             } catch (Exception minhaExcecao) {
                 minhaExcecao.printStackTrance)();
             } finally {
                 meuGrafico3D.releaseTarget();
                 flushGraphics();
             }
         }
     }
 }

Agora vamos usar o método setPerspective() para ajustar os atributos da câmera, o primeiro atributo será o ângulo de visão em graus (60 é a angulação padrão), o próximo campo será o aspecto da tela que será a largura da tela dividida pela autura, o terceiro campo é a distância em que a cena começará a ser renderizada (deve ser obrigatoriamente maior que zero), e por último é a distância máxima da renderização (o horizonte).

 import javax.io.*;
 import javax.microedition.lcdui.*;
 import javax.microedition.m3g.*;
 import javax.microedition.game.*;

 public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();
     Graphics3D meuGrafico3D = Graphics3D.getInstance();
     Object3D[] meuObjeto3D;
     World meuMundo;
     Camera minhaCamera;

     public ClasseMeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         try{
             meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
             minhaCamera = new Camera();
             minhaCamera.setPerspective(60.0f, (float)getWidth()/(float)getHeight(), 1.0f, 100.0f);
             meuMundo = (World) meuObjeto3D[0];
         }catch(Exception minhaExcessao){
             minhaExcessao.printStackTrance();
         }

         boolean gameOver = false;
         while(gameOver == false){
             try {
                 meuGrafico3D.bindTarget(meuGrafico);
                 meuGrafico3D.render(meuMundo);
                 meuThread.sleep(50);
             } catch (Exception minhaExcecao) {
                 minhaExcecao.printStackTrance)();
             } finally {
                 meuGrafico3D.releaseTarget();
                 flushGraphics();
             }
         }
     }
 }

Agora vamos adicionar o nosso objeto do tipo Camera para o mundo 3D, para isso vamos usar o método addChild() e entrar a nossa câmera como parâmetro.

 import javax.io.*;
 import javax.microedition.lcdui.*;
 import javax.microedition.m3g.*;
 import javax.microedition.game.*;

 public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();
     Graphics3D meuGrafico3D = Graphics3D.getInstance();
     Object3D[] meuObjeto3D;
     World meuMundo;
     Camera minhaCamera;

     public ClasseMeuGameCanvas() throws Exception {
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         try{
             meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
             minhaCamera = new Camera();
             minhaCamera.setPerspective(60.0f, (float)getWidth()/(float)getHeight(), 1.0f, 100.0f);
             meuMundo = (World) meuObjeto3D[0];
             meuMundo.addChild(minhaCamera);
         }catch(Exception minhaExcessao){
             minhaExcessao.printStackTrance();
         }

         boolean gameOver = false;
         while(gameOver == false){
             try {
                 meuGrafico3D.bindTarget(meuGrafico);
                 meuGrafico3D.render(meuMundo);
                 meuThread.sleep(50);
             } catch (Exception minhaExcecao) {
                 minhaExcecao.printStackTrance)();
             } finally {
                 meuGrafico3D.releaseTarget();
                 flushGraphics();
             }
         }
     }
 }

Por último agora que adicionamos a câmera ao mundo 3D, vamos dizer ao mundo 3D que queremos que essa câmera seja a câmera ativa, através do método setActiveCamera() entrando como parâmetro o nome da câmera.

 import javax.io.*;
 import javax.microedition.lcdui.*;
 import javax.microedition.m3g.*;
 import javax.microedition.game.*;

 public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();
     Graphics3D meuGrafico3D = Graphics3D.getInstance();
     Object3D[] meuObjeto3D;
     World meuMundo;
     Camera minhaCamera;

     public ClasseMeuGameCanvas() throws Exception {
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         try{
             meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
             minhaCamera = new Camera();
             minhaCamera.setPerspective(60.0f, (float)getWidth()/(float)getHeight(), 1.0f, 100.0f);
             meuMundo = (World) meuObjeto3D[0];
             meuMundo.addChild(minhaCamera);
             meuMundo.setActiveCamera(minhaCamera);
         }catch(Exception minhaExcessao){
             minhaExcessao.printStackTrance();
         }

         boolean gameOver = false;
         while(gameOver == false){
             try {
                 meuGrafico3D.bindTarget(meuGrafico);
                 meuGrafico3D.render(meuMundo);
                 meuThread.sleep(50);
             } catch (Exception minhaExcecao) {
                 minhaExcecao.printStackTrance)();
             } finally {
                 meuGrafico3D.releaseTarget();
                 flushGraphics();
             }
         }
     }
 }

Criando um triângulo

Vamos começar criando o mais simples dos polígonos, o triângulo, primeiramente na nossa classe vamos colocar o que aprendemos anteriormente.

 import javax.microedition.lcdui.*;
 import javax.microedition.m3g.*;
 import javax.microedition.game.*;

 public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();
     Graphics3D meuGrafico3D = Graphics3D.getInstance();
     Object3D[] meuObjeto3D;
     World meuMundo;
     Camera minhaCamera;

     public ClasseMeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         minhaCamera = new Camera();
         minhaCamera.setPerspective(60.0f, (float)getWidth()/(float)getHeight(), 1.0f, 100.0f);
         meuMundo.addChild(minhaCamera);
         meuMundo.setActiveCamera(minhaCamera);

         boolean gameOver = false;
         while(gameOver == false){
             try {
                 meuGrafico3D.bindTarget(meuGrafico);
                 meuGrafico3D.render(meuMundo);
                 meuThread.sleep(50);
             } catch (Exception minhaExcecao) {
                 minhaExcecao.printStackTrance)();
             } finally {
                 meuGrafico3D.releaseTarget();
                 flushGraphics();
             }
         }
     }
 }

VertexArray

O objeto do tipo VertexArray (array de vértices) é o tipo de objeto genérico que pode guardar coisas como a posição dos vértices, normais, texturas, etc...

Vértices

Primeiramente vamos criar um array do tipo short que irá armazenar os vértices X, Y e Z (nessa ordem) do nosso triângulo.

 import javax.microedition.lcdui.*;
 import javax.microedition.m3g.*;
 import javax.microedition.game.*;

 public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();
     Graphics3D meuGrafico3D = Graphics3D.getInstance();
     Object3D[] meuObjeto3D;
     World meuMundo;
     Camera minhaCamera;

     public ClasseMeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         minhaCamera = new Camera();
         minhaCamera.setPerspective(60.0f, (float)getWidth()/(float)getHeight(), 1.0f, 100.0f);
         meuMundo.addChild(minhaCamera);
         meuMundo.setActiveCamera(minhaCamera);

         short[] vetorVertices = {-1, 0, -1,      -1, 0, 1,      1, 0, -1}

         boolean gameOver = false;
         while(gameOver == false){
             try {
                 meuGrafico3D.bindTarget(meuGrafico);
                 meuGrafico3D.render(meuMundo);
                 meuThread.sleep(50);
             } catch (Exception minhaExcecao) {
                 minhaExcecao.printStackTrance)();
             } finally {
                 meuGrafico3D.releaseTarget();
                 flushGraphics();
             }
         }
     }
 }

Sabemos que o VertexArray pode guardar coisas como a posição dos vértices, normais, texturas, etc... no nosso caso iremos criar um objeto para armazenar a posição dos vértices. Como parâmetros do construtor iremos entrar:

  1. O número de vértices do VertexArray (como faremos um triângulo então teremos 3 vértices)
  2. O número de componentes por vértice (nesse caso são 3, os eixos X, Y e Z).
  3. O tamanho em bytes de cada componente (nesse caso 2, pois um short ocupa 2 bytes). OBS: O tamanho máximo é 2.
 import javax.microedition.lcdui.*;
 import javax.microedition.m3g.*;
 import javax.microedition.game.*;

 public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();
     Graphics3D meuGrafico3D = Graphics3D.getInstance();
     Object3D[] meuObjeto3D;
     World meuMundo;
     Camera minhaCamera;

     public ClasseMeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         minhaCamera = new Camera();
         minhaCamera.setPerspective(60.0f, (float)getWidth()/(float)getHeight(), 1.0f, 100.0f);
         meuMundo.addChild(minhaCamera);
         meuMundo.setActiveCamera(minhaCamera);

         short[] vetorVertices = {-1, 0, -1,      -1, 0, 1,      1, 0, -1}
         VertexArray arrayDePosicoes = new VertexArray(3, 3, 2);

         boolean gameOver = false;
         while(gameOver == false){
             try {
                 meuGrafico3D.bindTarget(meuGrafico);
                 meuGrafico3D.render(meuMundo);
                 meuThread.sleep(50);
             } catch (Exception minhaExcecao) {
                 minhaExcecao.printStackTrance)();
             } finally {
                 meuGrafico3D.releaseTarget();
                 flushGraphics();
             }
         }
     }
 }

Criamos o array dos vértices e criamos também o objeto do tipo VertexArray. Agora iremos colocar o array vetorVertices que criamos dentro do objeto VertexArray para isso iremos usar o método set() onde iremos entrar 3 parâmetros:

  1. O primeiro vértice do vetor vertices (nesse caso e quase sempre será zero)
  2. O número de vértices do VertexArray (como faremos um triângulo então teremos 3 vértices).
  3. O vetor de vértices (o que criamos short[] vertices).
 import javax.microedition.lcdui.*;
 import javax.microedition.m3g.*;
 import javax.microedition.game.*;

 public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();
     Graphics3D meuGrafico3D = Graphics3D.getInstance();
     Object3D[] meuObjeto3D;
     World meuMundo;
     Camera minhaCamera;

     public ClasseMeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         minhaCamera = new Camera();
         minhaCamera.setPerspective(60.0f, (float)getWidth()/(float)getHeight(), 1.0f, 100.0f);
         meuMundo.addChild(minhaCamera);
         meuMundo.setActiveCamera(minhaCamera);

         short[] vetorVertices = {-1, 0, -1,      -1, 0, 1,      1, 0, -1}
         VertexArray arrayDePosicoes = new VertexArray(3, 3, 2);
         arrayDePosicoes.set(0, 3, vetorVertices);

         boolean gameOver = false;
         while(gameOver == false){
             try {
                 meuGrafico3D.bindTarget(meuGrafico);
                 meuGrafico3D.render(meuMundo);
                 meuThread.sleep(50);
             } catch (Exception minhaExcecao) {
                 minhaExcecao.printStackTrance)();
             } finally {
                 meuGrafico3D.releaseTarget();
                 flushGraphics();
             }
         }
     }
 }
Normais

A exemplo do anterior primeiramente criamos um array do tipo short que agora irá armazenar a posição das noemais de cada vértice (127-padrão, 0-sem normal, -127-invertido) nesse caso como fizemos um triângulo plano vamos setar a normal padrão para o eixo Y (virado para cima).

 import javax.microedition.lcdui.*;
 import javax.microedition.m3g.*;
 import javax.microedition.game.*;

 public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();
     Graphics3D meuGrafico3D = Graphics3D.getInstance();
     Object3D[] meuObjeto3D;
     World meuMundo;
     Camera minhaCamera;

     public ClasseMeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         minhaCamera = new Camera();
         minhaCamera.setPerspective(60.0f, (float)getWidth()/(float)getHeight(), 1.0f, 100.0f);
         meuMundo.addChild(minhaCamera);
         meuMundo.setActiveCamera(minhaCamera);

         short[] vetorVertices = {-1, 0, -1,      -1, 0, 1,       1, 0, -1}
         VertexArray arrayDePosicoes = new VertexArray(3, 3, 2);
         arrayDePosicoes.set(0, 3, vetorVertices);

         short[] vetorNormais = {0, 127, 0,       0, 127, 0,      0, 127, 0}

         boolean gameOver = false;
         while(gameOver == false){
             try {
                 meuGrafico3D.bindTarget(meuGrafico);
                 meuGrafico3D.render(meuMundo);
                 meuThread.sleep(50);
             } catch (Exception minhaExcecao) {
                 minhaExcecao.printStackTrance)();
             } finally {
                 meuGrafico3D.releaseTarget();
                 flushGraphics();
             }
         }
     }
 }

Agora vamos criar o objeto VertexArray com os mesmos atributos no construtor (número de vertices do VextexArray, o numero de componentes de cada vértice, o tamanho em bytes de cada componente).

 import javax.microedition.lcdui.*;
 import javax.microedition.m3g.*;
 import javax.microedition.game.*;

 public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();
     Graphics3D meuGrafico3D = Graphics3D.getInstance();
     Object3D[] meuObjeto3D;
     World meuMundo;
     Camera minhaCamera;

     public ClasseMeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         minhaCamera = new Camera();
         minhaCamera.setPerspective(60.0f, (float)getWidth()/(float)getHeight(), 1.0f, 100.0f);
         meuMundo.addChild(minhaCamera);
         meuMundo.setActiveCamera(minhaCamera);

         short[] vetorVertices = {-1, 0, -1,      -1, 0, 1,       1, 0, -1}
         VertexArray arrayDePosicoes = new VertexArray(3, 3, 2);
         arrayDePosicoes.set(0, 3, vetorVertices);

         short[] vetorNormais = {0, 127, 0,       0, 127, 0,      0, 127, 0}
         VertexArray arrayDeNormais = new VertexArray(3, 3, 2);

         boolean gameOver = false;
         while(gameOver == false){
             try {
                 meuGrafico3D.bindTarget(meuGrafico);
                 meuGrafico3D.render(meuMundo);
                 meuThread.sleep(50);
             } catch (Exception minhaExcecao) {
                 minhaExcecao.printStackTrance)();
             } finally {
                 meuGrafico3D.releaseTarget();
                 flushGraphics();
             }
         }
     }
 }

E por fim, chamar novamente o método set() com os mesmos atributos (índice do primeiro vértice, o numero de vértice do VertexArray, o vetor de vértices).

 import javax.microedition.lcdui.*;
 import javax.microedition.m3g.*;
 import javax.microedition.game.*;

 public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();
     Graphics3D meuGrafico3D = Graphics3D.getInstance();
     Object3D[] meuObjeto3D;
     World meuMundo;
     Camera minhaCamera;

     public ClasseMeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         minhaCamera = new Camera();
         minhaCamera.setPerspective(60.0f, (float)getWidth()/(float)getHeight(), 1.0f, 100.0f);
         meuMundo.addChild(minhaCamera);
         meuMundo.setActiveCamera(minhaCamera);

         short[] vetorVertices = {-1, 0, -1,      -1, 0, 1,       1, 0, -1}
         VertexArray arrayDePosicoes = new VertexArray(3, 3, 2);
         arrayDePosicoes.set(0, 3, vetorVertices);

         short[] vetorNormais = {0, 127, 0,       0, 127, 0,      0, 127, 0}
         VertexArray arrayDeNormais = new VertexArray(3, 3, 2);
         arrayDeNormais.set(0, 3, vetorNormais);

         boolean gameOver = false;
         while(gameOver == false){
             try {
                 meuGrafico3D.bindTarget(meuGrafico);
                 meuGrafico3D.render(meuMundo);
                 meuThread.sleep(50);
             } catch (Exception minhaExcecao) {
                 minhaExcecao.printStackTrance)();
             } finally {
                 meuGrafico3D.releaseTarget();
                 flushGraphics();
             }
         }
     }
 }
Textura*

Por último vamos agora criar um vetor para as texturas.

 import javax.microedition.lcdui.*;
 import javax.microedition.m3g.*;
 import javax.microedition.game.*;

 public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();
     Graphics3D meuGrafico3D = Graphics3D.getInstance();
     Object3D[] meuObjeto3D;
     World meuMundo;
     Camera minhaCamera;

     public ClasseMeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         minhaCamera = new Camera();
         minhaCamera.setPerspective(60.0f, (float)getWidth()/(float)getHeight(), 1.0f, 100.0f);
         meuMundo.addChild(minhaCamera);
         meuMundo.setActiveCamera(minhaCamera);

         short[] vetorVertices = {-1, 0, -1,      -1, 0, 1,       1, 0, -1}
         VertexArray arrayDePosicoes = new VertexArray(3, 3, 2);
         arrayDePosicoes.set(0, 3, vetorVertices);

         short[] vetorNormais = {0, 127, 0,       0, 127, 0,      0, 127, 0}
         VertexArray arrayDeNormais = new VertexArray(3, 3, 2);
         arrayDeNormais.set(0, 3, vetorNormais);

         short[] vetorTexturas = {1, 0,       0, 0,       1, 1}

         boolean gameOver = false;
         while(gameOver == false){
             try {
                 meuGrafico3D.bindTarget(meuGrafico);
                 meuGrafico3D.render(meuMundo);
                 meuThread.sleep(50);
             } catch (Exception minhaExcecao) {
                 minhaExcecao.printStackTrance)();
             } finally {
                 meuGrafico3D.releaseTarget();
                 flushGraphics();
             }
         }
     }
 }

Vamos também criar o objeto do tipo VextexArray utilizando os mesmos atributos anteriores (número de vertices do VextexArray, o numero de componentes de cada vértice, o tamanho em bytes de cada componente).

 import javax.microedition.lcdui.*;
 import javax.microedition.m3g.*;
 import javax.microedition.game.*;

 public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();
     Graphics3D meuGrafico3D = Graphics3D.getInstance();
     Object3D[] meuObjeto3D;
     World meuMundo;
     Camera minhaCamera;

     public ClasseMeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         minhaCamera = new Camera();
         minhaCamera.setPerspective(60.0f, (float)getWidth()/(float)getHeight(), 1.0f, 100.0f);
         meuMundo.addChild(minhaCamera);
         meuMundo.setActiveCamera(minhaCamera);

         short[] vetorVertices = {-1, 0, -1,      -1, 0, 1,       1, 0, -1}
         VertexArray arrayDePosicoes = new VertexArray(3, 3, 2);
         arrayDePosicoes.set(0, 3, vetorVertices);

         short[] vetorNormais = {0, 127, 0,       0, 127, 0,      0, 127, 0}
         VertexArray arrayDeNormais = new VertexArray(3, 3, 2);
         arrayDeNormais.set(0, 3, vetorNormais);

         short[] vetorTexturas = {1, 0,       0, 0,       1, 1}
         VertexArray arrayDeTexturas = new VertexArray(2, 2, 2);

         boolean gameOver = false;
         while(gameOver == false){
             try {
                 meuGrafico3D.bindTarget(meuGrafico);
                 meuGrafico3D.render(meuMundo);
                 meuThread.sleep(50);
             } catch (Exception minhaExcecao) {
                 minhaExcecao.printStackTrance)();
             } finally {
                 meuGrafico3D.releaseTarget();
                 flushGraphics();
             }
         }
     }
 }

E por fim chamamos o método set() com os mesmos atributos (índice do primeiro vértice, o numero de vértice do VertexArray, o vetor de vértices).

 import javax.microedition.lcdui.*;
 import javax.microedition.m3g.*;
 import javax.microedition.game.*;

 public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();
     Graphics3D meuGrafico3D = Graphics3D.getInstance();
     Object3D[] meuObjeto3D;
     World meuMundo;
     Camera minhaCamera;

     public ClasseMeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         minhaCamera = new Camera();
         minhaCamera.setPerspective(60.0f, (float)getWidth()/(float)getHeight(), 1.0f, 100.0f);
         meuMundo.addChild(minhaCamera);
         meuMundo.setActiveCamera(minhaCamera);

         short[] vetorVertices = {-1, 0, -1,      -1, 0, 1,       1, 0, -1}
         VertexArray arrayDePosicoes = new VertexArray(3, 3, 2);
         arrayDePosicoes.set(0, 3, vetorVertices);

         short[] vetorNormais = {0, 127, 0,       0, 127, 0,      0, 127, 0}
         VertexArray arrayDeNormais = new VertexArray(3, 3, 2);
         arrayDeNormais.set(0, 3, vetorNormais);

         short[] vetorTexturas = {1, 0,       0, 0,       1, 1}
         VertexArray arrayDeTexturas = new VertexArray(2, 2, 2);
         arrayDeTexturas.set(0, 2, vetorTexturas);

         boolean gameOver = false;
         while(gameOver == false){
             try {
                 meuGrafico3D.bindTarget(meuGrafico);
                 meuGrafico3D.render(meuMundo);
                 meuThread.sleep(50);
             } catch (Exception minhaExcecao) {
                 minhaExcecao.printStackTrance)();
             } finally {
                 meuGrafico3D.releaseTarget();
                 flushGraphics();
             }
         }
     }
 }

Vertex buffer*

Criamos os arrays dos vértices, das normais e das texturas, agora precisamos agrupar esses arrays em um único buffer, por isso agora iremos criar um objeto do tipo VertexBuffer.

 import javax.microedition.lcdui.*;
 import javax.microedition.m3g.*;
 import javax.microedition.game.*;

 public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();
     Graphics3D meuGrafico3D = Graphics3D.getInstance();
     Object3D[] meuObjeto3D;
     World meuMundo;
     Camera minhaCamera;

     public ClasseMeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         minhaCamera = new Camera();
         minhaCamera.setPerspective(60.0f, (float)getWidth()/(float)getHeight(), 1.0f, 100.0f);
         meuMundo.addChild(minhaCamera);
         meuMundo.setActiveCamera(minhaCamera);

         short[] vetorVertices = {-1, 0, -1,      -1, 0, 1,       1, 0, -1}
         VertexArray arrayDePosicoes = new VertexArray(3, 3, 2);
         arrayDePosicoes.set(0, 3, vetorVertices);

         short[] vetorNormais = {0, 127, 0,       0, 127, 0,      0, 127, 0}
         VertexArray arrayDeNormais = new VertexArray(3, 3, 2);
         arrayDeNormais.set(0, 3, vetorNormais);

         short[] vetorTexturas = {1, 0,       0, 0,       1, 1}
         VertexArray arrayDeTexturas = new VertexArray(2, 2, 2);
         arrayDeTexturas.set(0, 2, vetorTexturas);

         VertexBuffer meuVertexBuffer = new VertexBuffer();

         boolean gameOver = false;
         while(gameOver == false){
             try {
                 meuGrafico3D.bindTarget(meuGrafico);
                 meuGrafico3D.render(meuMundo);
                 meuThread.sleep(50);
             } catch (Exception minhaExcecao) {
                 minhaExcecao.printStackTrance)();
             } finally {
                 meuGrafico3D.releaseTarget();
                 flushGraphics();
             }
         }
     }
 }

Agora para colocar o array de posições que criamos anteriormente vamos usar o método setPositions() da classe VertexBuffer, como parâmetros entraremos o objeto VertexArray, a escala (tamanho) do objeto e por fim o parâmetro null.

 import javax.microedition.lcdui.*;
 import javax.microedition.m3g.*;
 import javax.microedition.game.*;

 public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics meuGrafico = this.getGraphics();
     Graphics3D meuGrafico3D = Graphics3D.getInstance();
     Object3D[] meuObjeto3D;
     World meuMundo;
     Camera minhaCamera;

     public ClasseMeuGameCanvas(){
         super(false);
         meuThread = new Thread(this);
         meuThread.start();
     }
     public void run(){
         minhaCamera = new Camera();
         minhaCamera.setPerspective(60.0f, (float)getWidth()/(float)getHeight(), 1.0f, 100.0f);
         meuMundo.addChild(minhaCamera);
         meuMundo.setActiveCamera(minhaCamera);

         short[] vetorVertices = {-1, 0, -1,      -1, 0, 1,       1, 0, -1}
         VertexArray arrayDePosicoes = new VertexArray(3, 3, 2);
         arrayDePosicoes.set(0, 3, vetorVertices);

         short[] vetorNormais = {0, 127, 0,       0, 127, 0,      0, 127, 0}
         VertexArray arrayDeNormais = new VertexArray(3, 3, 2);
         arrayDeNormais.set(0, 3, vetorNormais);

         short[] vetorTexturas = {1, 0,       0, 0,       1, 1}
         VertexArray arrayDeTexturas = new VertexArray(2, 2, 2);
         arrayDeTexturas.set(0, 2, vetorTexturas);

         VertexBuffer meuVertexBuffer = new VertexBuffer();
         meuVertexBuffer.setPositions(arrayDePosicoes, 1.0f, null);

         boolean gameOver = false;
         while(gameOver == false){
             try {
                 meuGrafico3D.bindTarget(meuGrafico);
                 meuGrafico3D.render(meuMundo);
                 meuThread.sleep(50);
             } catch (Exception minhaExcecao) {
                 minhaExcecao.printStackTrance)();
             } finally {
                 meuGrafico3D.releaseTarget();
                 flushGraphics();
             }
         }
     }
 }

M3G/Modificando objetos 3D

Vamos entrar agora na parte de modificação dos objetos .m3g carregados no J2ME, vamos utilizar isso através do objeto for tipo World que criamos, na verdade esse objeto servirá como uma ponte de ligação entre o programador e os nódulos do objeto 3D em si.

Translação de um objeto

Vamos inicialmente aprender como translatar um nódulo do objeto 3D, quando se fala em translação você deve pensar em um movimento giratório que a Terra faz no sol, no mundo 3D não é bem assim, na verdade a translação nada mais é que a posição dos eixos x, y, z dentro do espaço.

Primeiramente vamos translatar a câmera que você criou e armazenou no arquivo .m3g, para isso vamos criar um objeto do tipo Camera() e inicializa-lo.

import javax.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;
    Camera minhaCamera = new Camera();

    public ClasseMeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
            meuMundo = (World) meuObjeto3D[0];
        } catch (Exception minhaExcessao) {
            minhaExcessao.printStackTrace();
        }

        boolean gameOver = false;
        while(gameOver == false){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                meuGrafico3D.render(meuMundo);
                meuThread.sleep(50);
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrace();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

Criamos a variável minhaCamera, mas nenhuma câmera foi colocada lá, agora vamos fazer isso através do nosso objeto do tipo World, utilizando o método getActiveCamera().

import javax.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;
    Camera minhaCamera = new Camera();

    public ClasseMeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
            meuMundo = (World) meuObjeto3D[0];
            minhaCamera = meuMundo.getActiveCamera();
        } catch (Exception minhaExcessao) {
            minhaExcessao.printStackTrace();
        }

        boolean gameOver = false;
        while(gameOver == false){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                meuGrafico3D.render(meuMundo);
                meuThread.sleep(50);
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrace();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

Agora com a câmera armazanada vamos movimenta-la, para isso só precisamos pegar emprestado da classe World o método setTranslation() que irá receber 3 variáveis float, que serão respectivamente o eixo x, y e z.

import javax.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;
    Camera minhaCamera = new Camera();

    public ClasseMeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
            meuMundo = (World) meuObjeto3D[0];
            minhaCamera = meuMundo.getActiveCamera();
        } catch (Excepetion minhaExcessao) {
            minhaExcessao.printStackTrace();
        }

        boolean gameOver = false;
        while(gameOver == false){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                minhaCamera.setTranslation(1.0f, 3.0f, 2.0f);
                meuGrafico3D.render(meuMundo);
                meuThread.sleep(50);
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrace();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

Pegando a translação de um objeto

Vamos ver agora como pegar a translação (posição dentro do mundo) de um objeto, vamos usar o mesmo exemplo anterior.

import javax.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;
    Camera minhaCamera = new Camera();

    public ClasseMeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
            meuMundo = (World) meuObjeto3D[0];
            minhaCamera = meuMundo.getActiveCamera();
        } catch (Exception minhaExcessao) {
            minhaExcessao.printStackTrace();
        }

        boolean gameOver = false;
        while(gameOver == false){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                minhaCamera.setTranslation(1.0f, 3.0f, 2.0f);
                meuGrafico3D.render(meuMundo);
                meuThread.sleep(50);
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrace();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

Vamos pegar a posição X, Y e Z da câmera, para isso vamos inicialmente criar um array float de 3 posições chamado posicaoCamera[], e inicia-lo com 0.

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;
    Camera minhaCamera = new Camera();

    public ClasseMeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
            meuMundo = (World) meuObjeto3D[0];
            minhaCamera = meuMundo.getActiveCamera();
        } catch (Exception minhaExcessao) {
            minhaExcessao.printStackTrace();
        }

        boolean gameOver = false;
        float[] posicaoCamera = {0.0, 0.0, 0.0};

        while(gameOver == false){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                minhaCamera.setTranslation(1.0f, 3.0f, 2.0f);
                meuGrafico3D.render(meuMundo);
                meuThread.sleep(50);
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrace();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

Agora dentro do loop principal vamos usar o método getTranslation() e entrar como parâmetro a variável float que criamos que vai pegar os 3 atributos X, Y e Z nessa ordem, como saída vamos dar um System.out.println() para exibir cada posição.

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;
    Camera minhaCamera = new Camera();

    public ClasseMeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
            meuMundo = (World) meuObjeto3D[0];
            minhaCamera = meuMundo.getActiveCamera();
        } catch (Exception minhaExcessao) {
            minhaExcessao.printStackTrace();
        }

        boolean gameOver = false;
        float[] posicaoCamera = {0.0, 0.0, 0.0};

        while(gameOver == false){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                minhaCamera.setTranslation(1.0f, 3.0f, 2.0f);
                minhaCamera.getTranslation(posicaoCamera);
                System.out.println(posicaoCamera[0]);
                System.out.println(posicaoCamera[1]);
                System.out.println(posicaoCamera[2]);
                meuGrafico3D.render(meuMundo);
                meuThread.sleep(50);
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrace();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

Orientação de um objeto

Vamos agora ver como orientar (rotacionar) um objeto 3D, vamos fazer como anteriormente, carregar o objeto, coloca-lo no objeto World e colocar a câmera na classe Camera.

 //arquivo ClasseMeuCanvas.java
 import java.io.*;
 import javax.microedition.lcdui.*;
 import javax.microedition.m3g.*;

 public class ClasseMeuCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics3D meuGrafico3D = Graphics3D.getInstance();
     Object3D[] meuObjeto3D;
     World meuMundo;
     Camera minhaCamera = new Camera();

     ClasseMeuCanvas(){
         super(false)
         meuThread = new Thread(this);
         meuThread.start();
     }

     public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
            meuMundo = (World) meuObjeto3D[0];
            minhaCamera = meuMundo.getActiveCamera();
        } catch (Exception minhaExcessao) {
            minhaExcessao.printStackTrace();
        }

        boolean gameOver = false;
        while(gameOver == false){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                meuThread.sleep(50);
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrace();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
     }
 }

Vamos agora utilizar o método setOrientation() e entrar como parâmetro respectivamente o angulo, o componente de roatação X, o componente de roatação Y e o componente de roatação Z. Esses componentes de rotação se colocados como 0 não irão alterar o eixo de rotação.

 //arquivo ClasseMeuCanvas.java
 import java.io.*;
 import javax.microedition.lcdui.*;
 import javax.microedition.m3g.*;

 public class ClasseMeuCanvas extends GameCanvas implements Runnable {
     Thread meuThread;
     Graphics3D meuGrafico3D = Graphics3D.getInstance();
     Object3D[] meuObjeto3D;
     World meuMundo;
     Camera minhaCamera = new Camera();

     ClasseMeuCanvas(){
         super(false)
         meuThread = new Thread(this);
         meuThread.start();
     }

     public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
            meuMundo = (World) meuObjeto3D[0];
            minhaCamera = meuMundo.getActiveCamera();
        } catch (Exception minhaExcessao) {
            minhaExcessao.printStackTrace();
        }

        boolean gameOver = false;
        while(gameOver == false){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                minhaCamera.setOrientation(10, 1, 2, 0);
                meuThread.sleep(50);
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrace();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
     }
 }

No exemplo a câmera irá girar 10 graus no eixo X, 20 graus no eixo Y, e 0 graus no eixo Z.

Pegando a orientação de um objeto

Vamos ver agora como pegar a orientação de um objeto, vamos usar o mesmo exemplo anterior.

import javax.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;
    Camera minhaCamera = new Camera();

    public ClasseMeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
            meuMundo = (World) meuObjeto3D[0];
            minhaCamera = meuMundo.getActiveCamera();
        } catch (Exception minhaExcessao) {
            minhaExcessao.printStackTrace();
        }

        boolean gameOver = false;
        while(gameOver == false){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                if (meuMundo != null) {
                    minhaCamera.setOrientation(10.0f, 0.0f, 1.0f, 2.0f);
                    meuGrafico3D.render(meuMundo);
                }
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrace();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

Vamos pegar a rotação X, Y e Z da câmera, para isso vamos inicialmente criar um array float agora de 4 posições chamado orientacaoCamera[], e inicia-lo com 0.

import javax.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;
    Camera minhaCamera = new Camera();

    public ClasseMeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
            meuMundo = (World) meuObjeto3D[0];
            minhaCamera = meuMundo.getActiveCamera();
        } catch (Exception minhaExcessao) {
            minhaExcessao.printStackTrace();
        }

        boolean gameOver = false;
        float[] orientacaoCamera = {0.0, 0.0, 0.0, 0.0};

        while(gameOver == false){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                if (meuMundo != null) {
                    minhaCamera.setOrientation(10.0f, 0.0f, 1.0f, 2.0f);
                    meuGrafico3D.render(meuMundo);
                }
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrace();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

Agora dentro do loop principal vamos usar o método getOrientation() e entrar como parâmetro a variável float que criamos que vai pegar os 4 atributos, como saída vamos dar um System.out.println() para exibir cada um.

import javax.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;
    Camera minhaCamera = new Camera();

    public ClasseMeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
            meuMundo = (World) meuObjeto3D[0];
            minhaCamera = meuMundo.getActiveCamera();
        } catch (Exception minhaExcessao) {
            minhaExcessao.printStackTrace();
        }

        boolean gameOver = false;
        float[] orientacaoCamera = {0.0, 0.0, 0.0, 0.0};

        while(gameOver == false){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                if (meuMundo != null) {
                    minhaCamera.setOrientation(10.0f, 0.0f, 1.0f, 2.0f);
                    minhaCamera.getOrientation(orientacaoCamera);
                    System.out.println(orientacaoCamera[0]);
                    System.out.println(orientacaoCamera[1]);
                    System.out.println(orientacaoCamera[2]);
                    System.out.println(orientacaoCamera[3]);
                    meuGrafico3D.render(meuMundo);
                }
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrace();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

Pegando um objeto específico

O World no M3G pode conter várias câmeras, meshes, luzes, etc, vamos ver aqui como pegar cada um desses objetos. Primeiramente é bom no seu editor 3D nomear cada objeto com um número, quando esse arquivo for salvo ficará mais fácil de você pegar a identificação do objeto através de um número inteiro.

Primeiramente vamos pegar os exemplos anteriores.

import javax.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;
    Camera minhaCamera = new Camera();

    public ClasseMeuGameCanvas(){
        super(false);
         meuThread = new Thread(this);
         meuThread.start();
    }
    public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
            meuMundo = (World) meuObjeto3D[0];
            minhaCamera = meuMundo.getActiveCamera();
        } catch (Exception minhaExcessao) {
            minhaExcessao.printStackTrace();
        }

        boolean gameOver = false;
        while(gameOver == false){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                if (meuMundo != null) {
                    meuGrafico3D.render(meuMundo);
                }
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrace();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

Agora vamos criar o objeto Node, que é o objeto que pode pegar a referência de uma câmera, mesh, luz, etc...

import javax.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;
    Camera minhaCamera = new Camera();
    Node meuNode;

    public ClasseMeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
            meuMundo = (World) meuObjeto3D[0];
            minhaCamera = meuMundo.getActiveCamera();
        } catch (Exception minhaExcessao) {
            minhaExcessao.printStackTrace();
        }

        boolean gameOver = false;
        while(gameOver == false){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                if (meuMundo != null) {
                    meuGrafico3D.render(meuMundo);
                }
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrace();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

Agora vamos usar o método getChild() no objeto World e entrar como parâmetro a idêntificação do objeto selecionado.

import javax.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;
    Camera minhaCamera = new Camera();
    Node meuNode;

    public ClasseMeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
            meuMundo = (World) meuObjeto3D[0];
            minhaCamera = meuMundo.getActiveCamera();
        } catch (Exception minhaExcessao) {
            minhaExcessao.printStackTrace();
        }
        meuNode = meuMundo.getChild(1);

        boolean gameOver = false;
        while(gameOver == false){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                if (meuMundo != null) {
                    meuGrafico3D.render(meuMundo);
                }
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrace();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

Agora usamos normalmente os métodos para modificar o Node, nesse caso vamos move-lo usando translate().

import javax.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;
    Camera minhaCamera = new Camera();
    Node meuNode;

    public ClasseMeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
            meuMundo = (World) meuObjeto3D[0];
            minhaCamera = meuMundo.getActiveCamera();
        } catch (Exception minhaExcessao) {
            minhaExcessao.printStackTrace();
        }
        meuNode = meuMundo.getChild(1);

        boolean gameOver = false;
        while(gameOver == false){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                if (meuMundo != null) {
                    meuNode.translate(0.0f, 0.0f, 0.1f);
                    meuGrafico3D.render(meuMundo);
                }
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrace();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

Animando um objeto 3D

Você colocou um objeto 3D para ser mostrado no seu aplicativo, mas se você criou um objeto animado deve ter notado que o objeto não expressou nenhum quadro da animação. Para fazer isso vamos usar o método animate() da classe World e receber como parâmetro, uma variavel int que irá incrementar a cada frame.

//arquivo ClasseMeuCanvas.java
import java.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;

public class ClasseMeuCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;

    public ClasseMeuCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }

    public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
            meuMundo = (World) meuObjeto3D[0];
        }catch(Exception minhaExcessao){
            minhaExcessao.printStackTrace();
        }

        int frame = 0;

        boolean gameOver = false;
        while(gameOver == false){
            try{
                meuGrafico3D.bindTarget(meuGrafico);
                meuGrafico3D.render(meuMundo);
                meuThread.sleep(50);
            } catch (Exception minhaExcessao) {
                minhaExcessao.printStackTrace();
            }finally{
                meuGrafico3D.releaseTarget();
                flusGraphics();
            }
        }
    }
}

Agora vamos chamar o método animate() e como parâmetro colocar uma variavel para a contagem do frame para a animação do objeto.

//arquivo ClasseMeuCanvas.java
import java.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;

public class ClasseMeuCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;

    public ClasseMeuCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }

    public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
            meuMundo = (World) meuObjeto3D[0];
        }catch(Exception minhaExcessao){
            minhaExcessao.printStackTrace();
        }

        int frame = 0;

        boolean gameOver = false;
        while(gameOver == false){
            try{
                meuGrafico3D.bindTarget(meuGrafico);
                meuMundo.animate(frame);
                meuGrafico3D.render(meuMundo);
                meuThread.sleep(50);
            }catch(Exception minhaExcessao){
                minhaExcessao.printStackTrace();
            }finally{
                meuGrafico3D.releaseTarget();
                frame++;
                flushGraphics()
            }
        }
    }
}

M3G/No Canvas

Preparando um gráfico no Canvas

Primeiramente dentro da nossa classe de Canvas vamos incluir o pacote M3G que tem todas as classes e métodos para se trabalhar com gráficos 3D.

import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;

Vamos agora criar normalmente nossa classe de Canvas.

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;

public class ClasseMeuCanvas extends Canvas {
}

Agora colocaremos o método paint() dentro da nossa classe de Canvas.

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;

public class ClasseMeuCanvas extends Canvas {
    public void paint(Graphics meuGrafico){
    }
}

E dentro do método paint() colocaremos o método repaint().

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;

public class ClasseMeuCanvas extends Canvas {
    public void paint(Graphics meuGrafico){
        repaint();
    }
}

Iniciando o gráfico 3D no Canvas

Até agora fizemos todo o preparativo para receber um gráfico canvas 2D, vamos agora iniciar um objeto do tipo Graphics3D com o método getInstance() dentro da nossa classe de Canvas.

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;

public class ClasseMeuCanvas extends Canvas {
    Graphics3D meuGrafico3D = Graphics3D.getInstance();

    public void paint(Graphics meuGrafico){
        repaint();
    }
}

Agora iniciaremos o nosso gráfico 3D dentro do método paint(), para isso vamos usar o método bindTarget() da classe Graphics3D, e vamos usar como parâmetro o objeto da classe Graphics.

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;

public class ClasseMeuCanvas extends Canvas {
    Graphics3D meuGrafico3D = Graphics3D.getInstance();

    public void paint(Graphics meuGrafico){
        meuGrafico3D.bindTarget(meuGrafico);
        repaint();
    }
}

Agora vamos terminar o processo de renderização do gráfico com o método releaseTarget() da classe Graphics3D, esse método deverá estar sempre APÓS a chamada do método bindTarget().

//arquivo ClasseMeuCanvas.java
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;

public class ClasseMeuCanvas extends Canvas {
    Graphics3D meuGrafico3D = Graphics3D.getInstance();

    public void paint(Graphics meuGrafico){
        meuGrafico3D.bindTarget(meuGrafico);
        meuGrafico3D.releaseTarget();
        repaint();
    }
}

Exibindo um objeto em 3D no Canvas

Vamos agora ver como exibir um objeto já criado, primeiro crie o seu objeto em 3D em algum programa a sua escolha depois salve o seu arquivo na mesma pasta do arquivo ClasseMeuCanvas.java. O processo é um pouco parecido com o de exibição de uma imagem na tela.

Agora primeiramente vamos incluir o pacote java.io que contém o tratamento de exceção.

//arquivo ClasseMeuCanvas.java
import java.io.*;
import javax.microedition.lcdui.*;
import java.microedition.m3g.*;

Agora vamos criar uma variável do tipo Object3D[].

//arquivo ClasseMeuCanvas.java
import java.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;

public class ClasseMeuCanvas extends Canvas {
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;

    public void paint(Graphics meuGrafico){
        meuGrafico3D.bindTarget(meuGrafico);
        meuGrafico3D.releaseTarget();
        repaint();
    }
}

Agora vamos criar o construtor da classe ClasseMeuCanvas jogando a exceção IOException que é necessário para inciarmos o nosso objeto.

//arquivo ClasseMeuCanvas.java
import java.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;

public class ClasseMeuCanvas extends Canvas {
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;

    ClasseMeuCanvas() throws IOException {
    }
    public void paint(Graphics meuGrafico){
        meuGrafico3D.bindTarget(meuGrafico);
        meuGrafico3D.releaseTarget();
        repaint();
    }
}

Agora vamos inicializar o nosso objeto meuObjeto3D dentro do construtor, usando a classe Loader com o método load() que irá receber como parâmetro o endereço da localização do arquivo 3D que vamos carregar.

//arquivo ClasseMeuCanvas.java
import java.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;

public class ClasseMeuCanvas extends Canvas {
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;

    ClasseMeuCanvas() throws IOException {
        meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
    }
    public void paint(Graphics meuGrafico){
        meuGrafico3D.bindTarget(meuGrafico);
        meuGrafico3D.releaseTarget();
        repaint();
    }
}

Agora poderíamos estar prontos para mostrar o objeto 3D na tela, mas calma, não é possível exibir objetos do tipo Object3D na tela, por isso devemos converter o nosso objeto meuObjeto3D para um tipo aceito para a renderização, nesse caso o tipo será da classe World que irá renderizar tudo dentro do nosso arquivo .m3g de uma vez, e que futuramente também será usado para modificar os atributos do arquivo .m3g. Por isso vamos primeiramente criar a nossa variável do tipo World.

//arquivo ClasseMeuCanvas.java
import java.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;

public class ClasseMeuCanvas extends Canvas {
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;

    ClasseMeuCanvas() throws IOException {
        meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
    }
    public void paint(Graphics meuGrafico){
        meuGrafico3D.bindTarget(meuGrafico);
        meuGrafico3D.releaseTarget();
        repaint();
    }
}

Agora dentro do construtor após a inicialização do objeto meuObjeto3D vamos converter o tipo Object3D[] para o tipo World.

//arquivo ClasseMeuCanvas.java
import java.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;

public class ClasseMeuCanvas extends Canvas {
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;

    ClasseMeuCanvas() throws IOException {
        meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
        meuMundo = (World) meuObjeto3D[0];
    }
    public void paint(Graphics meuGrafico){
        meuGrafico3D.bindTarget(meuGrafico);
        meuGrafico3D.releaseTarget();
        repaint();
    }
}

Agora sim, podemos exibir o objeto que criamos na tela, para isso dentro do método paint(), no espaço entre os métodos bindTarget() e releaseTarget() ficará todas as ações do módulo 3D. Para isso vamos usar nosso objeto da classe Graphics3D() e entrar o método render() que irá receber como parâmetro o nosso objeto do tipo World (que convertemos previamente).

//arquivo ClasseMeuCanvas.java
import java.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;

public class ClasseMeuCanvas extends Canvas {
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;

    ClasseMeuCanvas() throws IOException {
        meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
        meuMundo = (World) meuObjeto3D[0];
    }
    public void paint(Graphics meuGrafico){
        meuGrafico3D.bindTarget(meuGrafico);
            meuGrafico3D.render(meuMundo);
        meuGrafico3D.releaseTarget();
        repaint();
    }
}

M3G/No GameCanvas

Preparando um gráfico no GameCanvas

Inicializamos a ClasseMeuGameCanvas do mesmo jeito que fazemos com o GameCanvas normal, extendendo o GameCanvas, implementando o Runnable e colocando os objetos e métodos necessários.

import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();

    public ClasseMeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        boolean gameOver = false;
        while(!gameOver){
            try{
                meuThread.sleep(50);
            }catch(Exception minhaExcessao){
                minhaExcessao.printstackTrace();
            }finally{
                flushGraphics();
            }
        }
    }
}

Iniciando um gráfico 3D no GameCanvas

Vimos que a parte de inicialização do gráfico é igual a parte 2D, agora vamos criar o gráfico 3D em si, para isso vamos criar um objeto do tipo Graphics3D.

import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();

    public ClasseMeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        boolean gameOver = false;
        while(!gameOver){
            try{
                meuThread.sleep(50);
            }catch(Exception minhaExcessao){
                minhaExcessao.printStackTrace();
            }finally{
                flushGraphics();
            }
        }
    }
}

Agora nessa parte vamos fazer um pouco diferente do que em relação ao Canvas normal, para iniciar o gráfico 3D dentro do GameCanvas devemos obrigatoriamente criar um try-catch-finally dentro do método run(), nesse caso agora como a cada loop vamos sempre chamar o método flushGraphics() vamos coloca-lo dentro do finally.

import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();

    public ClasseMeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        boolean gameOver = false;
        while(!gameOver){
            try {
                meuThread.sleep(50);
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrace)();
            } finally {
                flushGraphics();
            }
        }
    }
}

Agora podemos chamar os métodos padrões do Graphics3D, primeiramente dentro do try vamos chamar o gráfico3D para inicializar o gráfico através do método bindTarget()

import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();

    public ClasseMeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        boolean gameOver = false;
        while(!gameOver){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                meuThread.sleep(50);
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrace)();
            } finally {
                flushGraphics();
            }
        }
    }
}

Agora vamos chamar o método releaseTarget() para soltar o gráfico 3D e deixar o programa correr normalmente, mas atente que faremos isso sempre dentro do finally, caso o programa não consiga inicializar o gráfico 3D.

import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();

    public ClasseMeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        boolean gameOver = false;
        while(!gameOver){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                meuThread.sleep(50);
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrace();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

Exibindo um objeto em 3D no GameCanvas

Vamos agora ver como exibir um objeto criado externamente dentro do GameCanvas, primeiro crie normalmente um objeto .m3g em algum editor externo (não se esqueça de colocar a câmera e a luz) e salve na mesma pasta da sua classe.

Agora vamos importar primeiramente o pacote java.io para o projeto.

import javax.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

Agora vamos criar a variável do tipo Object3D[].

import javax.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;

    public ClasseMeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        boolean gameOver = false;
        while(!gameOver){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                meuThread.sleep(50);
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrace();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

Agora dentro do método run(), mas antes do loop vamos criar um try-catch.

import javax.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;

    public ClasseMeuGameCanvas() throws Exception {
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        try{
        } catch(Exception minhaExcessao) {
            minhaExcecao.printStackTrace();
        }

        boolean gameOver = false;
        while(!gameOver){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                meuThread.sleep(50);
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrace();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

Agora vamos criar a variável do tipo Object3D[].

import javax.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;

    public ClasseMeuGameCanvas() throws Exception {
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
        } catch(Exception minhaExcessao) {
            minhaExcecao.printStackTrace();
        }

        boolean gameOver = false;
        while(!gameOver){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                meuThread.sleep(50);
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrace();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

Como sabemos, não se pode manipular objetos diretamente pelo Object3D[], temos que criar outro objeto do tipo World.

import javax.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;

    public ClasseMeuGameCanvas() throws Exception {
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
        } catch(Exception minhaExcessao) {
            minhaExcecao.printStackTrace();
        }

        boolean gameOver = false;
        while(!gameOver){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                meuThread.sleep(50);
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrace();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

Agora dentro do try-catch vamos converter o nosso objeto do tipo Object3D[] para o tipo World.

import javax.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;

    public ClasseMeuGameCanvas() throws Exception {
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
            meuMundo = (World) meuObjeto3D[0];
        } catch(Exception minhaExcessao) {
            minhaExcecao.printStackTrace();
        }

        boolean gameOver = false;
        while(!gameOver){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                meuThread.sleep(50);
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrance)();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

Agora vamos colocar o nosso World para ser renderizado no nosso gráfico 3D, vamos colocar o método render() dentro do run() logo após o bindTarget().

import javax.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
import javax.microedition.game.*;

public class ClasseMeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;
    Graphics meuGrafico = this.getGraphics();
    Graphics3D meuGrafico3D = Graphics3D.getInstance();
    Object3D[] meuObjeto3D;
    World meuMundo;

    public ClasseMeuGameCanvas() throws Exception {
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        try{
            meuObjeto3D = Loader.load("/Meu Objeto 3D.m3g");
            meuMundo = (World) meuObjeto3D[0];
        } catch(Exception minhaExcessao) {
            minhaExcecao.printStackTrace();
        }

        boolean gameOver = false;
        while(!gameOver){
            try {
                meuGrafico3D.bindTarget(meuGrafico);
                meuGrafico3D.render(meuMundo);
                meuThread.sleep(50);
            } catch (Exception minhaExcecao) {
                minhaExcecao.printStackTrance)();
            } finally {
                meuGrafico3D.releaseTarget();
                flushGraphics();
            }
        }
    }
}

Primeira aplicação

Neste artigo você irá aprender a criar a sua primeira classe para J2ME.

Importando

Para começarmos a fazer a nossa primeira aplicação (midlet) em J2ME vamos primeiramente importar a classe MIDlet para o nosso projeto.

import javax.microedition.midlet.*;

Criando a classe

Agora iremos criar a classe principal da nossa aplicação, ela irá extender a classe MIDlet, lembrando que o nome da classe sempre deverá ser o mesmo do arquivo .java.

import javax.microedition.midlet.*;

public class MinhaClasse extends MIDlet {
}

Métodos padrões

O ciclo de vida de uma aplicação para celular é sempre composta por 3 métodos startApp(), pauseApp() e destroyApp(boolean unconditional), vamos inseri-los dentro da nossa classe.

import javax.microedition.midlet.*;

public class MinhaClasse extends MIDlet {
    public void startApp() {
    }
    public void pauseApp() {
    }
    public void destroyApp(boolean unconditional) {
    }
}

O método startApp() funciona como o método main() no J2SE, ou seja, todas as instruções de execução ficarão dentro dele. Você também deve especificar o nome da MIDlet que contém os métodos de execução nas propriedades do projeto.

Execução dos métodos

Vamos agora mostrar a execução dos métodos através do console, para isso iremos usar normalmente o System.out.println() do pacote padrão do Java.

import javax.microedition.midlet.*;

public class MinhaClasse extends MIDlet {
    public void startApp() {
        System.out.println("Executando startApp");
    }
    public void pauseApp() {
        System.out.println("Executando pauseApp");
    }
    public void destroyApp(boolean unconditional) {
        System.out.println("Executando destroyApp");
    }
}

Você deve ter notado que foram executados apenas os métodos startApp() e destroyApp(), o pauseApp() não foi executado porque precisa de uma chamada especial para ser feita, como por exemplo uma ligação que o celular recebe enquanto o aplicativo está rodando.

Display

O objeto Display é o controlador do que é mostrado no dispositivo, ele está dentro do pacote javax.microedition.lcdui.

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class MinhaClasse extends MIDlet {
    Display meuDisplay;

    public void startApp() {
    }
    public void pauseApp() {
    }
    public void destroyApp(boolean unconditional) {
    }
}

Para criar fisicamente o objeto vamos chamar o método estático getDisplay().

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class MinhaClasse extends MIDlet {
    Display meuDisplay = Display.getDisplay(this);

    public void startApp() {
    }
    public void pauseApp() {
    }
    public void destroyApp(boolean unconditional) {
    }
}

Olá mundo

Fizemos várias coisas no projeto do programa, mas ainda não exibimos nada na tela, agora é a hora, nós vamos exibir a mensagem em um Form que é fácil de implementar, primeiro vamos instanciar o objeto Form.

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class MinhaClasse extends MIDlet {
    Display meuDisplay = Display.getDisplay(this);
    Form meuForm;

    public void startApp() {
    }
    public void pauseApp() {
    }
    public void destroyApp(boolean unconditional) {
    }
}

Agora vamos dar atributos ao objeto meuForm, nesse caso ele só tem um atributo que é a String de texto que será exibida na tela.

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class MinhaClasse extends MIDlet {
    Display meuDisplay = Display.getDisplay(this);
    Form meuForm = new Form("Título do Form. Olá mundo!");

    public void startApp() {
    }
    public void pauseApp() {
    }
    public void destroyApp(boolean unconditional) {
    }
}

Agora finalmente vamos exibir a mensagem na tela, para isso dentro do método startApp vamos colocar o objeto display, chamar o seu método setCurrent(), e colocar como atributo o objeto da classe Form.

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class MinhaClasse extends MIDlet {
    Display meuDisplay = Display.getDisplay(this);
    Form meuForm = new Form("Título do Form. Olá mundo!");

    public void startApp() {
        meuDisplay.setCurrent(meuForm);
    }
    public void pauseApp() {
    }
    public void destroyApp(boolean unconditional) {
    }
}

Redes

Vamos agora ver como trabalhar com redes para troca de dados no J2ME, podemos trabalhar com conexões de HTTP, Socket e Datagram. Para rodar os exemplos precisaremos na maioria dos casos de 2 midlets rodando ao mesmo tempo, e também precisaremos implementar loops que irão checar a chegada de novas informações.

Para iniciar, podemos usar normalmente a classe que criamos do GameCanvas e importando o pacote javax.microedition.io.

import javax.microedition.lcdui.game.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;

public class MeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;

    public MeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        boolean fim = false;
        while(fim == false){
            flushGraphics();
        }
    }
}

Primeiramente dentro do run() vamos instanciar um objeto do tipo Connector, vamos também inicia-lo com conteúdo vazio (null).

import javax.microedition.lcdui.game.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;

public class MeuGameCanvas extends GameCanvas implements Runnable {
    Thread meuThread;

    public MeuGameCanvas(){
        super(false);
        meuThread = new Thread(this);
        meuThread.start();
    }
    public void run(){
        Connection meuConnection = null;

        boolean fim = false;
        while(fim == false){
            flushGraphics();
        }
    }
}

Criando arquivos M3G no Blender

Neste tutorial vamos ver como criar um arquivo .m3g utilizando o Blender, um software gratuito de modelagem 3D.

O programa

Você pode baixar e instalar gratuitamente a versão completa do Blender em seu site oficial www.blender.org.

Blender Export for J2ME

A partir da versão 2.48 o Blender passou a vir com um exportador para o J2ME, para exportar seu objeto clique File -> Export -> M3G (.m3g, java) -> OK. Aparecerá uma janela com os seguintes atributos:

  • Texturing
    • Enabled - Permite a exportação de texturas
    • External - Referencia arquivos externos para texturas
  • Lightning
    • Enabled - Permite a exportação de luz
    • Ambient Light - Insere um objeto de luz extra para luz ambiente
  • Mesh Options
    • Autoscalling - Usa precisão máxima para posição de vértices
    • Persp. Correcti - Coloca uma flag de correção de perspectiva
    • Smooth Shading - Coloca uma flag de sombreamento suave
  • Posing
    • All Armature Ac - Exporta todas as ações para armaduras
  • Export
    • As Java Source - Exporta a cena como um código fonte em Java
    • M3G Version 2.0 - Arquivo M3G versão 2.0
    • Game Physics - Inclui informações de física de jogo para NOPE na exportação
    • O3D As JS - Gera um código em HTML e JavaScript que mostra a cena atual com o Google O3D API em um Browser
    • O3D As O3DTGZ

Ligações externas


Esta página é somente um esboço.
Ampliando-a você ajudará a melhorar o Wikilivros.