J2ME/Lições/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
[editar | editar código-fonte]Primeiramente vamos importar o pacote que contém a classe GameCanvas.
import javax.microedition.lcdui.game.*;
Agora vamos criar a classe MeuGameCanvas, estendendo 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
[editar | editar código-fonte]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
[editar | editar código-fonte]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
[editar | editar código-fonte]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
[editar | editar código-fonte]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
[editar | editar código-fonte]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
[editar | editar código-fonte]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();
}
}
}
}