Páginas

sexta-feira, 31 de agosto de 2012

Colocando uma musica de fundo no game

Games com musicas ficam bem mais interessantes.
O java possui recursos para a reprodução de arquivos .wav

Você pode executar uma musica com o seguinte código:

public void playWavLoop(URL wav) {
  try {
    AudioInputStream audioIn = AudioSystem.getAudioInputStream(wav);
    Clip clip = AudioSystem.getClip();
    clip.open(audioIn);
    clip.start();
    clip.loop(Clip.LOOP_CONTINUOUSLY);
  } catch (Exception ex) {
    ex.printStackTrace();
  }
}


Você usará este método passando um objeto URL representando a localização de seu arquivo .wav.
Nesse código, a música será carregada e executada em loop, o que é interessante em games, pois as durações das fases podem ser diferentes dependendo do rendimento do jogador. Ele também pode querer fazer outras coisas na fase, que fogem do objetivo principal. Mas a musica não pode parar.

Observe novamente meu jogo: https://sites.google.com/site/asteroidsrain/
A musica de fundo está rodando em loop, Utilizei este método acima para a reprodução dos arquivos wav.

Num post futuro explicarei como reproduzir os efeitos sonoros.

Att
Gustavo Marques.

Verificando colisões entre sprites

Nos jogos não basta os sprites se moverem pelo cenário ou apresentarem uma animação de imagens. Eles precisam interagir uns com os outros para termos um game mais interessante. Como fazer isso? Através de colisões!

Uma colisão ocorre quando dois objetos tem interseção em algum ponto do plano cartesiano (aquele gráfico x y).

Então com colisões, nós programadores podemos fazer que um sprite interaja com outro, quando tal colisão acontecer.

O java 2d facilita a detecção de colisões.
Vamos supor que estamos fazendo um simples jogo de futebol que consiste em levar a bola até o gol.
A bola é um sprite, o gol é outro.
Enquanto a bola se move pelo cenario nada acontece, porem quando ela colide com o sprite gol, um gol deve aparecer no placar.

A imagem da bola tem suas dimensões de altura e de largura. assim como o gol. A bola está numa posição x,y do plano cartesiano, o gol está em outro ponto.

Você pode tentar descobrir se colidiu no braço, se x da bola > x do gol, etc.etc.

Porém o Java facilita muito as coisas. A classe Rectangle possui o conveniente método intersects().
Vejamos como usar:
Crie esse método:

public boolean colide(Sprite sprite1, Sprite sprite2) {
  Rectangle r1 = new Rectangle(sprite1.getX(), sprite1.getY(), sprite1.getWidth(), sprite1.getHeight());
  Rectangle r2 = new Rectangle(sprite2.getX(), sprite2.getY(), sprite2.getWidth(), sprite2.getHeight());
  if (r1.intersects(r2)) {
    return true;
  }
  return false;
}


Agora para saber se houve colisão é só usa-lo:


if(colide(bola, gol)){
  //GOOOOOOOOOOOOOLLL
}

Até um próximo post.
Gustavo Marques.

quinta-feira, 30 de agosto de 2012

Criando animações de sprites

No post anterior eu expliquei como o GIMP pode ajudar a criar algumas imagens que servirão de efeitos no jogo.

E neste post eu expliquei como o Blender pode criar uma sequencia de imagens a serem utilizadas em nossos sprites.

Agora irei explicar como animar as imagens.
Para entendermos isso precisamos entender primeiro como funciona um jogo. Todo jogo tem o seu game loop, um loop que fica rodando o tempo todo enquanto o game executa.

A estrutura básica de um game simplificadamente pode ser assim:


carregandoImagens();//carrega as imagens do jogo
boolean gameRodando = true;
while(gameRodando){
  atualizaEstadoDoJogo();//Atualizamos as posições dos sprites
  renderizaTelaDoJogo();//pintamos na tela os sprites na nova posição
}


Podemos entender cada loop como um frame do jogo.

O método  carregandoImagens () carrega as imagens a serem usadas no jogo.
O método  atualizaEstadoDoJogo() atualiza a logica do game de acordo com os inputs e/ou outros fatores.
E o método renderizaTelaDoJogo() finalmente pinta na tela o estado do jogo no frame corrente.

É por causa do game loop que podemos fazer animações de images. Lembra de como se fazia um desenho animado antigamente? Pegava-se um caderno e em cada folha desenhava-se o personagem de um jeito. Então ao folhear o caderno tinha-se a ilusão da animação. Isso se aplica ao game loop, como?

Bom, podemos entender cada volta no loop como uma folha. Então em um frame (ou volta no loop) desenhamos a imagem de um jeito, e no proximo frame a mesma imagem levemente modificada, e assim até termos uma animação.

Veja novamente meu jogo em https://sites.google.com/site/asteroidsrain/ perceba os asteroids rodando, as explosões, a nave virando etc. Isso nada mais é do que imagens levemente diferentes em cada frame.

Mas como fazer isso na pratica?
Fiz um pequeno framework de animação. Ele nos dá alguns controles de animações interessantes.

Pense no seguinte: cada volta no loop é executada muito rapidamente, assim se em cada frame você colocar uma parte diferente de sua sequencia de imagens, a animação vai acabar num piscar de olhos. Você precisa ter um controle de delay.
Outro problema: E se a animação for constante? Como os asteroids que ficam rodando o tempo todo? Então ao chegar na ultima imagem deve-se voltar para a primeira

Essa pequena classe que criei ajuda nesses dois problemas. Vamos ao código:


import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
public class ImageAnimation {
    private List<BufferedImage> images = new ArrayList<BufferedImage>();
    private final int LOOP = 1;
    private int type = 0;
    private int delay = 0;
    private int currentdelay = 0;
    private int currentPosition = 0;
    public BufferedImage getCurrentImage(){
        if(currentPosition == 0){
            //ja pode retornar a primeira
        }else{
            if(delay > 0){
                //verifica se já é hora da proxima
                if(currentdelay == delay){
                    //chegou a hora, volta o delay para  zero
                    currentdelay = 0;
                    //proxima imagem
                    currentPosition++;
                }else{
                    //AINDA NÃO É A HORA
                    currentdelay++;
                }
            }else{
                //não tem delay, vai para a proxima
                currentPosition++;
            }
        }
        //verifica se saiu do tamanho da lista
        if(currentPosition >= images.size()){
            //passou do ultimo, verifica se é loop
            if(type == LOOP){
                //volta para a primeira imagem
                currentPosition = 0;
            }else{
                //acabou a animação
                return null;
            }
        }
        return images.get(currentPosition);
    }
    public void setImages(List<BufferedImage> images) {
        this.images = images;
    }
    public void setType(int type) {
        this.type = type;
    }
    public void setDelay(int delay) {
        this.delay = delay;
    }
}


Como podemos usar ela no jogo, veja abaixo:


List<BufferedImage> imagens = carregandoImagens ();//carrega as imagens do jogo
//configura a classe de animação
ImageAnimation animacao = new ImageAnimation();
animacao.setImages(imagens);
animacao.setDelay(30);
animacao.setType(ImageAnimation.LOOP);
//entra no game loop
boolean gameRodando = true;
while(gameRodando){            
   atualizaEstadoDoJogo();//Atualizamos as posições dos sprites
   //obtem aqui a proxima imagem da animacao
   BufferedImage imagem = animacao. getCurrentImage ();
   renderizaTelaDoJogo(imagem);//pintamos na tela a imagem corrente
}


Vamos entender esse código.
Na configuração da classe de animação eu passo as imagens que compõe minha animação utilizando o método animacao.setImages(imagens);.
Também informo que o delay será de 30 voltas no método animacao.setDelay(30), isso quer dizer que o framework de animação deverá esperar 30 voltas antes de entregar a próxima imagem. E finalmente informo que o tipo de animação será LOOP em  animacao.setType( ImageAnimation.LOOP ); , isso quer dizer que ao entregar a ultima imagem, o framework voltará seu ponteiro para primeira, reiniciando assim a animação. Se o parametro LOOP não fosse fornecido a animação acabaria na ultima imagem, retornando null após isso.

Espero que esse post tenha esclarecido o processo de animação.
No próximo post explicarei como pintar na tela imagens utilizando o java 2D

Att
Gustavo Marques.

Usando o GIMP para efeitos de luz

O GIMP pode ser bastante útil no desenvolvimento de jogos.

No post anterior eu expliquei como usar o blender para geração de sprites 3D, porém decidi que a nave irá ter seu propulsor de movimento e que os tiros dela serão um lazer.

Para fazer esse efeito, abra o gimp, crie um novo arquivo nas dimensões que desejar. Adicione uma camada de transparencia. Depois selecione tudo com control+A e delete. Voce terá uma área transparente.

Agora vá em filtros, efeitos de luz e sombra e selecione clarão em gradiente. Defina o tipo de clarão bem como os parametros de tamanho e rotação. Clique em ok e você terá um resultado como este:


Salve então essa imagem como png.
Você ainda pode ainda criar outras do mesmo tipo e tamanho porém com angulos de rotação diferentes. Assim você terá imagens o suficiente para fazer uma animação.

Veja meu jogo em: https://sites.google.com/site/asteroidsrain/

Coloquei esses efeitos durante o jogo e ficou muito agradável.
Até um próximo post

Gustavo Marques

Usando o Blender no desenvolvimento de Jogos 2D

Neste post irei mostrar o uso do Blender como ferramenta de apoio no desenvolvimento de jogos 2D com efeitos 3D.

Para ver o resultado final deste jogo que eu criei acesse: https://sites.google.com/site/asteroidsrain/

Eu criei no blender um modelo de uma nave, conforme abaixo:



No blender depois que você aprende a fazer extrusões e usar as teclas G, R, S já faz muita coisa.
Uma vez que meu modelo foi criado então eu posiciono a camera 3D de modo que o angulo de visão dela seja a lateral da nave. Feito isso teclamos a tecla I, que irá guardar a posição atual na timeline de animação.
Posição 1:


Depois posicionamos a vista da camera para a traseira da nave, avançamos um pouco o marcador da timeline e teclamos novamente em I para guardar essa segunda posição.
Posição 2:


Feito isso então, no mode de exportação em png, pressionamos control+f12 para executar a animação exportando cada quadro.
Eis o resultado:


O Blender trabalha com interpolação, isso quer dizer que ele irá calcular as posições intermediárias entre o ponto inicial e o final. Quanto maior o valor em quadros por segundo, mais imagens intermediarias serão geradas entre os dois pontos.

O Blender certamente facilita o trabalho. Esse movimento da nave leva em consideração reflexão de luz, deslocamento de sombra etc. Esses detalhes são difíceis de desenhar no braço.

De posse desses sprites, é só usar a programação na sua linguagem de preferencia para fazer a animação delas. Para saber como fazer a animação desses sprites gerador, consulte este post.

Espero que tenham gostado dessa dica, uso isso bastante nos jogos que eu faço.
No próximo post explicarei como usar o GIMP para acrescentar outros efeitos no jogo

Att,
Gustavo Marques.

Advergames

Muitos programadores gostam de programar seus próprios jogos, porém alguns fazem isso só por hobby ou divertimento, não pensando no mercado de games das grandes industrias de softwares. Porém existe um nicho dentro do desenvolvimeto de games que é mais acessivel, devido ao fato de grande parte dos jogos serem de menor porte. Me refiro aos advergames.

Sabe o que é Advergames?
Assista a esse video no youtube e tire suas conclusões:



Pode-se fazer advergames mais simples, com flash ou applets. Depende do investimento e objetivos.
Depois eu faço um post de um tutorial de criação de games em java.

Para conferir algumas dicas de desenvolvimento de games, clique aqui

Gustavo Marques.

Use as libs commons da apache

A fundação apache possui muitas libs para java: commons-io, commons-lang, commons-log etc.
Porém muitos programadores usam essas libs somente como dependencias dos frameworks que utilizam.

A verdade é que essas libs possuem muitos métodos úteis para os programadores finais.
Como exemplo vou citar a commons-io.

Como ler e gravar arquivos em java? Pode confessar que você já se perdeu no meio dos InputStream, BufferedRead, FileWriter etc etc.

O jar commons-io tem uma classe que simplifica nosso trabalho com arquivos: org.apache.commons.io.FileUtils. Ela possui vários métodos estáticos realmente úteis.

Os que envolvem leitura e gravação de arquivos são estes:


//LEITURA

static byte[] readFileToByteArray(File  file)
          //Reads the contents of a file into a byte array.

static String readFileToString(File  file)
          //Reads the contents of a file into a String using the default encoding for the VM.

static String readFileToString(File  file, String  encoding)
          //Reads the contents of a file into a String.

static List  readLines(File  file)
          //Reads the contents of a file line by line to a List of Strings using the default encoding for the VM.

static List  readLines(File  file, String  encoding)
          //Reads the contents of a file line by line to a List of Strings.

//GRAVAÇÃO

static void writeByteArrayToFile(File  file, byte[] data)
          //Writes a byte array to a file creating the file if it does not exist.

static void writeLines(File  file, Collection  lines)
          //Writes the toString() value of each item in a collection to the specified File line by line.

static void writeLines(File  file, Collection  lines, String  lineEnding)
         //Writes the toString() value of each item in a collection to the specified File line by line.

static void writeLines(File  file, String  encoding, Collection  lines)
          //Writes the toString() value of each item in a collection to the specified File line by line.

static void writeLines(File  file, String  encoding, Collection  lines, String  lineEnding)
          //Writes the toString() value of each item in a collection to the specified File line by line.

static void writeStringToFile(File  file, String  data)
          //Writes a String to a file creating the file if it does not exist using the default encoding for the VM.

static void writeStringToFile(File  file, String  data, String  encoding)
          //Writes a String to a file creating the file if it does not exist.


Estão aí, prontos para serem usados
att

Gustavo Marques.

Desenvolvimento de Games: Carregando imagens ao iniciar o jogo


O seu jogo provavelmente usará imagens nos sprites.

Para carrega-las você talvez use: (em java)

URL url = UmaClasse.class.getResource("imagem.png"); //ou de uma url qualquer
BufferedImage imagem = ImageIO.read(url);
g.drawImage(imagem, x, y, null);//desenha no graphcs


Porém esse código apresenta um custo operacional alto, pode ser acesso ao disco ou acesso a internet.
Se em cada ponto do game voce utilizar esse código para exibir imagens, seu jogo não será fluído, mas ficará travando.


Então uma boa dica é você carregar todas as imagens logo no inicio do jogo e guardá-las na memória. Se forem muitas imagens use um JProgress para mostrar que o game não travou.


Pode-se utilizar um map para guardar as imagens.


//inicio do jogo
//Map que vai guardar as imagens
HashMap<String, BufferedImage> imagens = new HashMap<String, BufferedImage>();

URL url = UmaClasse.class.getResource("imagem.png"); //ou de uma url qualquer
imagens.put("imagem1", ImageIO.read(url));

url = UmaClasse.class.getResource("imagem2.png"); //ou de uma url qualquer
imagens.put("imagem2", ImageIO.read(url));

//então use o map para pegar as imagens
//desenhando a imagem guardada
g.drawImage(imagens.get("imagem1"), x, y, null);//desenha no graphcs


Isso sem duvida vai melhorar a fluidez do seu jogo.

Mas talvez você se pergunte: Como eu mesmo posso fazer as imagens que utilizarei em meu jogo?
No próximo post explicarei como o Blender poderá ajudá-lo

Att,
Gustavo Marques.

Veja também

Related Posts Plugin for WordPress, Blogger...