Aljava é um framework Java desenvolvido para o ensino de Orientação a Obejtos tendo como foco o desenvolvimento de jogos. O Framework também pode ser usado como uma biblioteca de classes úteis que dentre outras coisas realizam o desenho de formas geométricas, imagens, execução de sons e colisões envolvendo Retângulos.
O framework pode ser dividido nas seguintes seções
- Desenho, Tela e Utilitáros: Métodos usados para desenhar formas geométricas utilizando diversas cores, recursos de transparência e colisão, além de métodos para recuperar textos e números informados pelos usuários. Outros métodos utilitários como um sorteador de números também estão disponíveis;
- Mídia: Classes para desenho de imagens, animações e execução de sons;
- Elementos de Jogo: Classes para construção de cenários, realização de colisão, tratamento de gravidade;
- Framework: Uso das quatro classes responsáveis por transformar o Aljava em um mini Framework para o desenvolvimento de jogos.
Esta seção descreve questões iniciais básicas para o uso do Aljava nos seus projetos.
Basta adicionar ao seu projeto o arquivo Aljava.jar que está disponível aqui. Ele tem tudo que é necessário.
Para iniciar com a classe Alj basta importá-la e executar alguns dos seus comandos. Ao importar a classe uma janela de 400x400 é criada para o jogo, todos os comandos são baseados nesta janela.
import aljava.Alj;
Segue abaixo alguns exemplos de comandos disponíveis na classe Alj.
Alj.desenha.retangulo(0, 0, 400, 400);
Alj.cor.nome("verde");
Alj.desenha.texto(20, 200, "Aljava - Programação é massa.", 16);
Alj.tela.exibe();
Obs: Para que um desenho efetivamente seja exibido na tela, o método Alj.tela.exibe() deve ser executado.
Além dos comandos da classe "Alj" existem diversas outras classes que podem ser utilizadas conforme documentado nas seções abaixo.
A lib Aljava está em um JAR. Você pode incluí-lo em seu projeto e começar a usá-lo livremente. Qualquer ambiente de programação (Netbeans, Eclipse, JCreator, etc) pode ser utilizado. Para fins didáticos, recomenda-se o BlueJ.
No BlueJ, eventualmente ocorre um erro ao tentar exibir uma janela em função de erros de acesso ao contexto gráfico. Para evitá-los, basta resetar a máquina virtual sempre antes de executar um código novamente.
Toda esta seção está disponível através de comandos acessados a partir da classe "Alj". Os comandos estão divididos em grupos conforme descrição abaixo:
desenho: Desenho de formas geométricas básicas (retângulos, triângulos, ovais, linhas e polígonos). Também é possível desenhar textos com tamanhos de fonte variados; cor: comandos que alteram a cor que está sendo utilizada para o desenho. A cor pode ser alterada usando valores hexadecimais, RGB ou mesmo através de algumas Strings padronizadas. Também é possível informar o nível de transparência de uma cor; transforma: Comandos que permitem o uso de rotações nas imagens desenhadas; tela: Comandos para solicitar informações ao usuário e demais operações ligadas a janela principal do jogo; mouse: Métodos de acesso ao mouse; tecla: Métodos de acesso ao teclado; util: comandos utilitários como o sorteio de números aleatórios.
Todos os métodos de desenho utilizam a cor que foi definida. Inicialmente a cor definida é preto, para alterá-la, veja a seção "Cores".
Uma linha representa a ligação entre dois pontos. Os parâmetros são o x, y do ponto inicial e o x, y do ponto final.
//assinatura do método
Alj.desenha.linha(int x, int y, int xFinal, int yFinal);
//Linha diagonal na tela
Alj.desenha.linha(0, 0, 400, 400);
//Linha horizontal no meio da tela
Alj.desenha.linha(0, 400, 200, 200);
Um retângulo inicia com o canto superior esquerdo em uma coordenada x, y e possui uma largura e uma altura.
//assinatura do método
Alj.desenha.retangulo(int x, int y, int largura, int altura);
//Um retângulo de 300 de largura por 100 de altura no ponto 20, 20
Alj.desenha.retangulo(20, 20, 300, 100);
Também é possível desenhar somente o contorno da borda do retângulo. Os parâmetros são os mesmos.
//assinatura do método
Alj.desenha.retanguloBorda(int x, int y, int largura, int altura);
//Um retângulo de 300 de largura por 100 de altura no ponto 20, 20
Alj.desenha.retanguloBorda(20, 20, 300, 100);
Uma oval inicia com o canto superior esquerdo em uma coordenada x, y e possui uma largura e uma altura.
//assinatura do método
Alj.desenha.oval(int x, int y, int largura, int altura);
//Uma oval de 300 de largura por 100 de altura no ponto 20, 20
Alj.desenha.oval(20, 20, 300, 100);
Uma triângulo inicia com o canto superior esquerdo em uma coordenada x, y e possui uma largura e uma altura. Este triângulo sempre tem a ponta para cima. Para construir triângulos de lado ou para baixo, use-o em conjunto com o comando Alj.transforma.rotaciona( ... ) apresentado na seção "Transformações".
//assinatura do método
Alj.desenha.trinagulo(int x, int y, int largura, int altura);
//Uma triângulo de 300 de largura por 100 de altura no ponto 20, 20
Alj.desenha.triangulo(20, 20, 300, 100);
Você pode desenhar qualquer forma geométrica usando polígonos. Polígonos são sequencias de pontos. Para desenhar um polígono, basta passar um array de pontos x e um array de pontos y.
//Assinatura do método
//Alj.desenha.poligono(int x[], int y[]);
int xs[] = {100, 200, 300, 150, 100};
int ys[] = {100, 100, 200, 150, 100};
Alj.desenha.poligono(xs, ys);
Alternativamente, você pode usar um objeto da classe Polygon.
//não esqueça de importar a classe Polygon para usá-la
//Ex: import java.awt.Polygon;
Polygon pol = new Polygon();
pol.addPoint(100, 100);
pol.addPoint(400, 350);
pol.addPoint(200, 150);
pol.addPoint(100, 100);
Alj.desenha.poligono(pol);
Textos podem ser desenhados em qualquer posição X, Y da tela. Alternativamente, você pode informar um quarto parâmetro para o tamanho da fonte. Não é possível mudar a fonte dos textos e a quebra de linha também não é feita pelo método.
//Assinatura do método
Alj.desenha.texto(int x, int y, String texto);
//ou
Alj.desenha.texto(int x, int y, String texto, int tamanhoFonte);
Alj.desenha.texto(20, 200, "Aljava - Programação que vale o esforço.", 16);
Todos os desenhos acima podem receber transparência ou uma cor. Você pode mudar a cor de diversas formas, escolha a que preferir.
Existem alguns nomes de cores pré-definidos que podem ser usados como uma String. Isso é útil no início do aprendizado de programação, principalmente para os primeiros exercícios.
//Assinatura do método
Alj.cor.nome(String nomeCor);
//Usando a cor vermelha
Alj.cor.nome("vermelho");
As cores disponíveis são: "vermelho", "laranja", "ciano", "preto", "azul", "amarelo", "verde", "magenta" e "branco".
Uma cor é formada por uma quantidade de vermelho (R), verde (G) e azul (B). Estes valores variam de 0 (mais escuro) até 255 (mais claro). Este comando tem três parâmetros, um para cada das três cores e é o mais útil para criar pequenas animações com cores.
//Assinatura do método
Alj.cor.rgb(int r, int g, int b)
//Inforando uma cor com alta quantidade de vermelho
Alj.cor.rgb(200, 100, 10);
Desenvolvedores que tenham conhecimento de web e estejam acostumados com o formato hexadecimal, podem usá-lo também. Qualquer cor hexadecimal pode ser informada como uma String.
//Assinatura do método
Alj.cor.hexadecimal(String hexadecimal);
//Exemplo de uma cor tendendo para o verde
Alj.cor.hexadecimal("#336699");
Desenvolvedores mais avançados podem usar um objeto da classe Color do Java.
//Assinatura do método
Alj.cor.objeto(Color cor);
//Exemplo da mesma cor informada pelo formato RGB
Alj.cor.objeto( new Color(200,100,10) );
Outro recurso útil é o uso de transparências. Você pode informar a transparência com uma porcentagem que varia de 0 até 100. Quanto maior o valor, maior a transparência.
//Assinatura do método
Alj.cor.transparencia(int porcentagem);
//Exemplo de 50% de transparência
Alj.cor.transparencia(50);
O objetivo deste grupo de comandos e poder realizar transformações como escala e rotação nos desenhos, por hora, somente rotação está disponível.
A rotação é sempre aplicada diretamente ao ambiente de desenho. Desse modo, é sempre importante informar qual o eixo x, y que será utilizado para a rotação.
//Assinatura do método
Alj.transforma.rotaciona(int angulo, int xCentra, int yCentral);
Se você quiser uma determinada forma geométrica seja rotacionada, precisará rotacionar a tela usando como eixo o centro da figura, e, após o desenho, limpar a rotação para que ela não afete os próximos desenhos.
Exemplo de um losango (Quadrado rotacionado em 90 graus).
//Define x e y da posição central da rotação
int xCentral = x + (largura / 2);
int yCentral = y + (altura / 2);
//Executa Rotação
Alj.transforma.rotaciona(90, xCentral, yCentral);
//Faz o desenho
Alj.desenha.retangulo(x, y, largura, altura);
//Limpa a rotação para que os próximos desenhos não sejam afetados.
Alj.transforma.limpaRotacao();
A Aljava é sempre baseada em uma tela. Os comandos deste pacote ajudam a trabalhar com ela e com entrada de dados que devem vir do usuário através de janelas pop-up.
Todos os desenhos só serão exibidos na tela após a execução deste método. Antes disso, ficam em um buffer de desenho escondido. Isso evita que a tela fique "piscando".
//Lembre-se de sempre executar este método após desenhar qualquer coisa (que você queira ver na tela).
Alj.tela.exibe();
Antes de iniciar o desenho de um novo frame da sua aplicação, você pode querer limpar a tela. Basicamente limpar a tela é desenhar um retângulo branco por cima de tudo. Este método é um atalho para isso.
Alj.tela.limpar();
A tela tem por padrão 400 pixels de largura por 400 de altura. Para alterar este tamanho, use:
//Alj.inicializa(int largura, int altura)
Alj.inicializa(800, 600);
OBS: Este método não usa o grupo "tela" na assinatura pois a intenção é no futuro transformá-lo em um inicializador da janela.
Para encerrar o programa e fechar a janela, execute:
Alj.tela.finalizar();
Frequentemente é útil exibir mensagens ao usuário como "Parabéns, você venceu.". Para isto, use:
Alj.tela.exibeMensagem("Parabéns, você venceu.\n\nTente novamente.")
Obs: use \n para quebra de linha na janela.
Você também pode solicitar que o usuário lhe informe um texto qualquer, como por exemplo, o seu nome.
String nome = Alj.tela.solicitaTexto("Por favor, informe seu nome.");
Você também pode solicitar que o usuário lhe informe um número qualquer, como por exemplo, para um par ou ímpar.
int numero = Alj.tela.solicitaNumero("1, 2, 3 e já...");
Alternativamente, você pode solicitar um double
double numero = Alj.tela.solicitaNumeroDouble("Informe o preço do produto:");
O mouse é um dos recursos que possibilitam maior interação com o usuário. Sempre que necessário você pode pegar a posicão x, y do mouse com os métodos:
int x = Alj.mouse.x();
int y = Alj.mouse.y();
E pode ver também se um dos três botões do mouse foram pressionados
if( Alj.mouse.clickE() ){
Alj.tela.exibeMensagem("Você pressionou o botão esquerdo");
}
if( Alj.mouse.clickM() ){
Alj.tela.exibeMensagem("Você pressionou o botão do meio");
}
if( Alj.mouse.clickD() ){
Alj.tela.exibeMensagem("Você pressionou o botão direito");
}
Por enquanto a Aljava só permite saber se em um dado momento, uma tecla está ou não pressionada.
if( Alj.tecla.press("esquerda") ){
moveHorizontal(-10);
}
if( Alj.tecla.press("direita") ){
moveHorizontal(+10);
}
if( Alj.tecla.press("cima") ){
moveVertical(-10);
}
if( Alj.tecla.press("baixo") ){
moveVertical(+10);
}
As teclas disponíveis com String são: "enter", "espaco", "esquerda", "direita", "cima","baixo", todas as letras de "a" até "z", todos os números de 0 até 9 e todos os números do "NUMPAD" através das Strings "NUMPAD0", "NUMPAD2", etc.
Alternativamente, você pode usar o código da tecla com as constantes da classe KeyEvent do Java.
if( Alj.tecla.press( KeyEvent.VK_TAB ) ){
executaEspecial();
}
Neste grupo estão alguns comandos utilitários que não se encaixam em nenhum dos grupos anteriores.
Em jogos, é muito comum precisarmos pedir para o computador esperar alguns instantes antes de executar uma ação ou partir para o frame seguinte do jogo. Podemos fazer isso, esperando alguns milisegundos com:
Alj.util.espera(500);
Você pode sortear um número entre um mínimo e um máximo.
int num = Alj.util.sorteia(1, 10);
Alternativamente, você pode sortear um double passando valores double como parâmetros
double num = Alj.util.sorteia(1.5, 3.5);
Encerramos o detalhamento dos comandos com os utilitários. Agora, seguem alguns exemplos utilizando comandos de diferentes pacotes.
//Cria uma variável para o valor da trasnparência.
//Inicialmente os desenhos começarão transparentes
int transparencia = 100;
//Inicia loop que irá desenhar as formas geométricas uma vez para cda valor inteiro entre 100 e 0.
while(transparencia > 0){
transparencia -= 1;
//Limpa telae e configura cor laranja
Alj.tela.limpa();
Alj.cor.rgb(255, 200, 100);
//Desenha um texto informando o valor da transparência com uma linha abaixo para dar um estilo visual agradável. Este texto deve estar sempre exibido, portanto, sua transparência é 0
Alj.cor.transparencia(0);
Alj.desenha.texto(10, 28, "Transparência: "+transparencia, 20);
Alj.desenha.linha(10, 42, 290, 42);
//Desenha as três formas geométricas mais básicas com o valor da transparência conforme a variável "transparência"
Alj.cor.transparencia(transparencia);
Alj.desenha.retangulo(20, 170, 40, 40);
Alj.desenha.oval(200, 60, 40, 40);
Alj.desenha.triangulo(100, 120, 40, 40);
//Desenha um polígono usando 5 pontos
//Coordenadas x e y do polígono, Ex: 100,100 -> 200, 100 -> 300, 200, etc...
int xs[] = {100, 200, 300, 150, 100};
int ys[] = {100, 100, 200, 150, 100};
Alj.desenha.poligono(xs, ys);
//Exibe os desenhos
Alj.tela.exibe();
//Faz uma pausa para demosntrar o efeito da animação
Alj.util.espera(50);
}
while(true){
int xMouse = Alj.mouse.x();
int yMouse = Alj.mouse.y();
//Sempre desenha um pequeno círculo na posição do mouse
Alj.desenha.oval(xMouse - 1, yMouse - 1, 2, 2);
//Se o botão esquerdo estiver pressionado,
//desenha um círculo vermelho maior
if (Alj.mouse.clickE()) {
Alj.cor.rgb(255, 0, 0);
Alj.desenha.oval(xMouse - 10, yMouse - 10, 20, 20);
}
//Se o botão do meio estiver pressionado
//desenha um círculo verde maior
if (Alj.mouse.clickM()) {
Alj.cor.rgb(0, 255, 0);
Alj.desenha.oval(xMouse - 10, yMouse - 10, 20, 20);
}
//Se o botão do direito estiver pressionado
//desenha um círculo azul maior
if (Alj.mouse.clickD()) {
Alj.cor.rgb(0, 0, 255);
Alj.desenha.oval(xMouse - 10, yMouse - 10, 20, 20);
}
Alj.tela.exibe();
}
Alj.tela.exibeMensagem("Olá. Pressione Enter para mudar a largura e altura da janela.");
//Inicializa uma janela com a largura e altura padrão
int largura = 740;
int altura = 180;
String textoQualquer = "Aqui vai um texto que você informar";
Alj.inicializa(largura, altura);
//Entra no loop para esperar o usuário pressionar enter
while(true){
Alj.tela.limpa();
//Quando o enter for pressionado, pega uma nova largura, uma nova altura e o texto a ser exibido
if(Alj.tecla.press("enter")){
largura = Alj.tela.solicitaNumero("Informe a largura:");
altura = Alj.tela.solicitaNumero("Informe a altura:");
textoQualquer = Alj.tela.solicitaTexto("Ïnforme um texto qualquer:");
//e re-inicializa a janela com a altura especificada
Alj.inicializa(largura, altura);
}
//Desenha a largura e a altura da janela
String tamanhoTela = largura+" x "+altura;
Alj.desenha.texto(20, 60, tamanhoTela, 40);
//Desenha o texto informado
Alj.desenha.texto(20, 100, textoQualquer, 40);
//Exibe
Alj.tela.exibe();
Alj.util.espera(50);
}
Por hora, podem ser usadas mídias para imagens e sons. Cada arquivo de mídia é representado por um objeto de uma classe. Todos os arquivos utilizados devem estar na pasta raiz do projeto.
Importe as classes desta seção usando "import aljava.midia.*".
Uma imagem representa um arquivo que pode estar nos formatos "png", "jpg" ou "gif". Uma imagem possui métodos para desenhá-la, alterar largura, altura ou invertê-la.
Imagem img;
//...
img = new Imagem("pasta/nomeimagem.jpg");
//Método para desenhar a imagem em uma posição na tela
//img.desenha(int x, int y);
img.desenha(20, 20);
//Métodos de acesso à largura e altura da imagem
int largura = img.pegaLargura();
int altura = img.pegaAltura();
//Métodos que modificam a largura e altura
img.alteraLargura( 1 ); //Aumenta em 1 pixel a largura da imagem
img.alteraAltura( -1 ); //Diminui em um pixel a altura da imagem
//img.alteraTamanho(int novaLargura, int nova Altura)
img.alteraTamanho(48, 48); //Redimensiona a imagem para os valores especificados
//Inverte a imagem
img.inverte();
Um objeto da classe Gif é uma extensão da classe Imagem e tem como única finalidade permitir que um objeto Gif pare de ser desenhado após certo período de tempo. Este recurso é útil por exemplo, em Gif's de explosões que devem parar de ser exibidos após alguns milissegundos.
//new Gif(String caminhoImagem, int tempoParaSumirEmMilissegundos);
Gif explosao = new Gif("explosao.gif", 2000);
//Além dos métodos de imagem, há um método disponível para saber se o tempo já terminou
if( explosao.temrinou() ){
//faz alguma coisa..
}
//Outro método útil é o reinicia, que permite reiniciar o contador de tempo do Gif
explosao.reinicia();
Uma animação corresponde a um conjunto de imagens, cada qual representando um quadro, sendo exibidas uma após a outra com um certo intervalo de tempo. Por ser uma coleção de imagens, estão disponíveis alguns métodos que alteram todas as imagens da animação.
//Cria um objeto da classe Animação informando o tempo em milissegundos de intervalo entre as imagens
Animacao animacao = new Animacao(200);
//Adiciona diferentes imagens para a animação
animacao.addImagem("imagens/ryu/chute.png");
animacao.addImagem("imagens/ryu/chute2.png");
animacao.addImagem("imagens/ryu/chute.png");
animacao.addImagem("imagens/ryu/soco_direita.png");
animacao.addImagem("imagens/ryu/soco_esquerda.png");
animacao.addImagem("imagens/ryu/haduken.png");
//Inicia execução da animação em loop, ou seja, quando chegar ao final, recomeça
//Uma forma alternativa é usar o método inicia() apenas.
animacao.iniciaEmLoop();
//Para demonstrar os demais recursos fazemos um loop que altera a animação conforme as teclas digitadas pelo usuário
while(true){
Alj.tela.limpa();
if( Alj.tecla.press("esquerda") ){
//Diminui em 10 pixels a largura de todas as imagens da animação
animacao.alteraLargura(-10);
}
if( Alj.tecla.press("direita") ){
//Aumenta em 10 pixels a largura de todas as imagens da animação
animacao.alteraLargura(10);
}
if( Alj.tecla.press("cima") ){
//Aumenta em 10 pixels a altura de todas as imagens da animação
animacao.alteraAltura(10);
}
if( Alj.tecla.press("baixo") ){
//Diminui em 10 pixels a altura de todas as imagens da animação
animacao.alteraAltura(-10);
}
if( Alj.tecla.press("espaco") ){
//Inverte todas as imagens da animação
animacao.inverte();
}
//Processa a animação para realizar a troca do quadro
animacao.processa();
//Desenha a imagem atual da animação no ponto 50, 50 da tela
animacao.desenha(50, 50);
Alj.tela.exibe();
}
Um som pode ser executado, parado, reiniciado e executado em loop. Somente estão disponíveis sons no formato Wav. Segue abaixo exemplo de como controlar uma música via comandos do teclado.
//Cria objeto que representa uma música
Som musica = new Som("recursos/aljava.exemplos.som/mario.wav");
while(true){
Alj.tela.limpa();
Alj.desenha.texto(20, 20, "Pressione t -> Toca a Musica");
if(Alj.tecla.press("t")){
musica.toca();
//se preferir, inicie em loop
//musica.loop();
}
Alj.desenha.texto(20, 40, "Pressione p -> Pausa a Musica");
if(Alj.tecla.press("p")) {
musica.pausa();
}
Alj.desenha.texto(20, 60, "Pressione r -> Reinicia a Musica");
if(Alj.tecla.press("r")) {
musica.reinicia();
}
Alj.tela.exibe();
}
Outro uso é como sons de notas musicais para simular um violão ou guitarra por exemplo. Neste exemplo, para cada tecla digitada um objeto som é criado e executado, assim, uma mesma tecla pode ser pressionada várias vezes para criar diversos objetos do mesmo som.
Variáveis booleanas são utilizadas para garantir que a tecla só pode ser pressionada novamente após ser solta.
while(true){
Alj.tela.limpa();
//Tecla Ré
Alj.desenha.texto(20, 40, "Pressione s -> Ré");
if(Alj.tecla.press("s") && sLiberado){
sLiberado = false;
Som som = new Som("recursos/aljava.exemplos.som/re_piano.wav");
som.toca();
}
if(!Alj.tecla.press("s")) {
sLiberado = true;
}
//Tecla Ré
Alj.desenha.texto(20, 60, "Pressione d -> Fá");
if(Alj.tecla.press("d") && dLiberado){
dLiberado = false;
Som som = new Som("recursos/aljava.exemplos.som/fa_piano.wav");
som.toca();
}
if(!Alj.tecla.press("d")) {
dLiberado = true;
}
Alj.tela.exibe();
}
As classes desta seção apresentam elementos importantes para o desenvolvimento de jogos, como colisões e cenários.
São apresentados aqui somente os métodos mais importantes. Para mais métodos, verifique o JavaDoc.
Importe as classes desta seção usando import aljava.jogo.*.
A Classe Retangulo é a classe base da maioria dos objetos e contém quatro variáveis (x, y, largura e altura). Ela possui métodos de acesso e modificadores para cada uma das 4 variáveis, métodos para movimentar o X e o Y e métodos para colisão. Geralmente você usará esta classe como superclasse de outras
public class MeuObjeto extends Retangulo {
//Código da classe aqui
}
//Ao usar o seu objeto, os seguintes métodos da classe Retangulo estarão disponíveis
//Você pode criar objetos da classe Retangulo por um construtor vazio ou com quatro parâmetros, um para cada uma das variáveis
//MeuObjeto obj = new MeuObjeto(x, y, largura, altura);
MeuObjeto obj = new MeuObjeto();
//Métodos de acesso
int x = obj.pegaX();
int y = obj.pegaY();
int largura = obj.pegaLargura();
int altura = obj.pegaAltura();
//Métodos modificadores
obj.alteraX( 30 );
obj.alteraY( 30 );
obj.alteraLargura( 48 );
obj.alteraAltura( 48 );
Abaixo, métodos que podem ser usados para movimentar e verificar colisões
//Movimento do X e do Y
if( Alj.tecla.press("esquerda") ){
obj.moveX(-10); //Move o x dez pixels para a esquerda
}
if( Alj.tecla.press("baixo") ){
obj.moveY(10); //Move o y dez pixels para baixo.
}
//Colisão.
//Com outro objeto que também seja um retangulo
if(obj.toca( outroObjetoRetangulo )){
//faz alguma coisa
}
//Com um determinado ponto, por exemplo, o X, Y do mouse
int xMouse = Alj.mouse.x();
int yMouse = Alj.mouse.y();
if(obj.toca(xMouse, yMouse)){
//Faz alguma coisa
}
Esta classe estende a classe Retangulo e adiciona métodos para processar a gravidade e realizar pulos.
public class MeuObjeto extends RetanguloGravidade { /*...*/ }
//...
MeuObjeto obj = new MeuObjeto();
while(true){
//processa gravidade
obj.processa();
//Pula ao pressionar espaço
if(Alj.tecla.press("espaco")){
//O 15 é a força do pulo
obj.pula(15);
}
}
Para que a gravidade funciona são necessários o valor do chão e o próprio valor da gravidade. Estes valores podem ser alterados via variáveis públicas estáticas.
//O padrão para o chão é 400
RetanguloGravidade.CHAO = 380;
//O padrão da gravidade é 1
RetanguloGravidade.GRAVIDADE = 0.7;
Uma CenaComColisao é uma extensão da classe Cena. A classe CenaComColisao se diferencia apenas por acrescentar colisão, porém, como verificou-se que nenhum dos projetos em sala utilizava somente a classe Cena, somente está documentada a classe CenaComColisao.
Uma CenaComColisao consiste em um conjunto de "tiles" (pequenos quadrados representados por imagens) desenhados a partir de um arquivo de configuração e que podem ser sólidos ou não.
Objetos do tipo Retangulo podem ser adicionados ao Cenário e movimentados com ele.
Segue abaixo exemplo de um arquivo de configuração de uma cena:
Arquivo cena.txt
2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
2,2,2,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,2,2
1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,2,2,1,1,1,1,2,2,2,1,1
1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,1,1,2,2,1,1,1,1,1,2,2,2,2,1,2,2,2,1,1,1,1
1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,2,2,2,2,2,2,1,1,1,1,2,2,2,2,2
1,1,1,1,1,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,1,1,2,2,2,2,2,2,2
1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1
1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,1,1,2,2,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,1
1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,2,1,1,2,2,3,2,2,2,1,1,1,1,2,2,2,2,2
1,1,1,1,1,2,2,2,2,1,1,1,1,2,1,1,1,1,1,1,1,2,2,2,2,3,3,3,2,1,1,2,2,2,2,2,2,2
2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,2,2,2,2,2,2,2
2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,2,2,2,2,2,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2
Para desenhar este cenário é usado o seguinte código:
CenaComColisao cena1;
//...
cena1 = new CenaComColisao("cena.txt");
//Configura que todos os números 1 usarão a imagem terra.png
cena1.configTile(1, "terra.png");
//Configura imagem do número 2 informando o terceiro parâmetro como verdadeiro, isso significa que este bloco é sólido
cena1.configTile(2, "fundo.jpg", true);
//Faz uma parede fantasma usando a mesma imagem do bloco sólido, porém, sem solidez
cena1.configTile(3, "fundo.jpg");
//Configura o tamanho de cada Tile.
cena1.tamanhoTiles(32, 32);
Além disso podemos adicionar objetos que realizam colisão com os tiles do cenário e objetos que são movimentados junto do cenário, ou seja, se o cenário se mover para a esquerda os objetos se movem junto, executando o efeito dos objetos estarem realmente dentro do cenário. As duas operações são diferentes e são feitas com os seguintes métodos.
//Adiciona objetos para realizar colisão com o cenário
cena1.adicionaObjeto(jogador);
cena1.adicionaObjeto(inimigo1);
cena1.adicionaObjeto(inimigo2);
//Adiciona objetos que se movimentarão junto do cenário
//O jogador não é incluído porque ele deve ficar fixo na tela e quem se move na verdad eé o cenário. Esta tarefa é feita pela classe camera.
cena1.moveComCenario(inimigo1);
cena1.moveComCenario(inimigo2);
Obs: Todos os objetos adicionados devem ser do tipo Retangulo.
Por fim, no loop do jogo, o cenário deve ser processado para realizar os cálculos de colisão e movimento dos objetos.
...
cena1.processa();
cena1.desenha();
...
A classe Camera implementa a lógica de, a partir do movimento de um determinado retangulo, movimentar o cenário para ter a sensação de que existe uma câmera acompanhando o objeto.
Para usá-la, basta informar um objeto da classe Cena e outro da Classe Retangulo.
Camera cam = new Camera(cena1, jogador);
Para que os cálculos de acompanhamento da câmera sejam realizados, basta executar o método "processa".
...
cam.processa();
...
As classes desta seção devem usadas em conjunto para construir uma arquitetura escalável de jogo, com diversas fases e objetos.
Importe as classes desta seção usando import aljava.jogo.*.
A classe motor gera objetos que controlam o fluxo principal do jogo e realizam a troca de fases.
Por jogo, é ideal que só exista um objeto da classe motor disponível. Para isso, esta classe implementa o padrão singleton, que garante apenas um único objeto disponível para toda a aplicação. De qualquer local do código o motor do jogo pode ser recuperado através de:
Motor motor = MotorSingleton.pegaInstancia();
Para incluir fases no motor basta usar o método "adicionaFase" informando a chave e o correspondente objeto que implementa a interface Fase.
//Cria objetos de classes que implementam a interface Fase
TelaInicial t = new TelaInicial( senhorq );
Fase1 f = new Fase1( senhorq );
Fase2 f2 = new Fase2( senhorq );
FaseChefao c = new FaseChefao( senhorq );
//Recupera objeto motor
Motor motorJogo = MotorSingleton.pegaInstancia();
//Adiciona as fases existentes,
//todas implementando a interface Fase
motorJogo.adicionaFase("telaInicial", t);
motorJogo.adicionaFase("fase1", f);
motorJogo.adicionaFase("fase2", f2);
motorJogo.adicionaFase("faseChefao", c);
Para executar o motor, basta informar a fase inicial e opcionalmente, o número de quadros por segundo.
motorJogo.defineFaseInicial("telaInicial");
motorJogo.alteraQuadrosPorSegundo(50);
motorJogo.executa();
Para trocar de fase, basta executar o seguinte método, informando a chave da próxima fase:
Motor motorJogo = MotorSingleton.pegaInstancia();
motorJogo.defineProximaFase("fase2");
A interface Fase contém três métodos que devem ser implementados:
- processa: Contém a lógica da fase;
- desenha: desenha os objetos da fase;
- inicia: Método executado sempre antes de de fazer o primeiro processamento da fase. Também é executado quando a fase é definida como "próxima".
public class MinhaFase implements Fase {
//...
public void inicia(){
//Garate que sempre que voltar para essa fase o jogador iniciará em X = 40
jogador.alteraX(40);
}
public void processa(){
jogador.processa();
inimigo.processa();
processaColisoes();
verificaVitoria();
}
public void desenha(){
jogador.desenha();
inimigo.desenha();
}
//...
}
Esta classe contém dois métodos abstratos, o processa para a lógica do objeto e o desenha. A classe estende a classe "RetanguloGravidade" e tem métodos para informar e recuperar se um objeto está "vivo" no jogo.
public class Tiro extends ObjetoJogo {
//...
public void processa(){
x += 1;
}
public void desenha(){
Alj.cor.nome("preto");
Alj.desenha.oval(x, y, largura, altura);
}
//...
}
Esta classe permite criar um contador de milissegundos.
//Cria um objeto para contar o tempo a cada 2 segundos
ContadorTempo cont = new ContadorTempo(2000);
if(cont.terminou()){
//Faz alguma coisa e..
cont.reinicia();
}
Todos os comandos e classes aqui apresnetados tem como mesmo objetivo, tornar a programação em java um pouco mais divertida e prazerosa para quem está começando.
Assim, nossos primeiros programas podem ganhar um pouco mais de vida e dinamismo e o ensino fica melhor também para o professor que pode ir muito além do tradicional.
E tudo isso, ainda usando Java, uma linguagem poderosa e profissional. Espero que gostem.
À criatividade e disposição dos meus alunos que tem encarado comigo o desafio de aprender programação de um modo que vale a pena, divertido, voltado para aproveitar o máximo do potencial criativo que o computador pode nos oferecer.
Ao SENAI São José e à Márcia Cristina (coordenadora) pela confiança e pelo excepcional trabalho como coordenadora do curso técnico de programação articulado com o ensino médio.
Aos projetos BlueJ, Greenfoot, idraw e Processing.
Ao orientador do meu TCC, professor Ricardo Pereira e Silva, UFSC e aos demais professores do curso de Sistemas de Informação que contribuíram para o meu aprendizado e desenvolvimento.
Por fim, à minha amada família, Suélen e Kainan, simplesmente pelo que são.!
Linhas apenas, para completar, 1000 linhas no arquivo. até mais.