Cristiano Trindade Segunda-feira, 02 de setembro de 2002

Criando animações

Uma animação nada mais é do que uma sequência de quadros (também chamados de frames) que simula um movimento. Podemos criar animações simples repetindo imagens e exibindo-as uma após a outra. Utilizando o laço for, por exemplo, poderemos exibir uma sequência de frames que irá simular um movimento, como no código a seguir:

public class animacao extends Applet
{
public void start()
{
for (animframe = 0; animframe < nenhum_dos_frames;
animframe ++)
{
// configura um quadro
setup_animacao_frame(animframe);
// redesenhando a tela para um novo quadro
repaint()
// faz um intervalo de 0,1 segundos (100 milionesimos de segundo) entre cada frame
try
{
Thread.sleep (100);
} catch (InterruptedException e) {};
}
}
// outras instruções
}

Esse código possui um problema: a chamada do método repaint() não desenha imediatemente na tela. Java coleta solicitações para pintar a tela de maneira que possa executá-las quando não existirem outros eventos para serem processados. Como o laço for do método start() não permite que sejam enviadas mensagens de evento, Java não poderá repintar a tela até que seja finalizado o laço for. Para contornar este problema, criaremos uma linha de execução (thread), como mostra o código seguinte:

public class animacao extends Applet implements Runnable
{
Thread anime = null;
public void start()
{
anime = new Thread(this);
anime.start();
}
public void run()
{
for (animframe = 0; animframe < nenhum_dos_frames;
animframe ++)
{
// configurando o quadro
setup_animacao_frame (animframe);
// redesenhando a tela
repaint();
// faz um intervalo de 0,1 segundos (100 milionésimos de segundo) entre os frames
try
{
Thread.sleep (100);
} catch (InterruptedException e) {};
}
}
// outras instruções
}

O exemplo anterior implementa a interface Runnable, que permite a execução de uma linha independente.

Vejamos agora uma animação completa escrita em Java (marquee.java). Nesta aplicação, a string “Aprendendo Java” aparece atravessando a janela do applet da esquerda para a direita. Para executar o movimento, a string será redesenhada na tela a cada 0,1 segundos (100 milésimos de segundo). Esse efeito é semelhante àquele gerado pela tag <MARQUEE> em HTML.

import java.applet.*;
import java.awt.*;
public class marquee extends Applet implements Runnable
{
int xpos = 0;
Thread anime = null;
Image file_img;
public void start()
{
if (anime = null)
{
anime = new Thread(this);
anime.start();
}
}
public void paint(Graphics g)
{
while (anime != null)
{
xpos+= 10;
if (xpos > size().width)
xpos = 0;
repaint();
try
{
Thread.sleep (100);
}
catch (InterruptedException e) {};
}
}
}

Como podemos ver, a string é redesenhada na tela a cada 0,1 segundos utilizando-se cada vez uma coordenada x diferente.
Esta mesma técnica de redesenhar sequências de objetos na tela pode ser utilizada com imagens. Vejamos agora um exemplo (logogif.java) de um logotipo Java animado em três dimensões. Para isso, usaremos seis imagens .gif, que serão redesenhadas a cada 0,2 segundos (200 milionésimos de segundo).

import java.applet.*;
import java.awt.*;
public class logogif extends Applet implements Runnable
{
int img_index = 0;
Thread anime = null;
String im_nomes[] = (“java1.gif”, “java2.gif, “java3.gif”, “java4.gif”,
“java5.gif”, “java6.gif”};
mage java_img[] = new Image[6];
public void init()
{
for (int i = 0; i < 6; i++)
java_img[i] = getImage (getCodeBase(), img_nomes[i]);
}
public void start()
{
if (anime = null)
{
anime = new Thread(this);
anime.start();
}
}
public void paint (Graphics g)
{
g.drawImage (java_img[img_index], 0, 0, this);
}
public void run()
{
while (anime != null)
{
img_index++;
if (img_index > 5)
img_index = 0;
repaint();
try
{
Thread.sleep(200);
}
catch (InterruptedException e) {};
}
}
}

Quando você executar este applet, irá notar uma certa cintilação (conhecida como flickering). O flickring é o resultado do desaparecimento de toda a área do desenho com a cor de fundo. Quando o código chama o método repaint() para redesenhar a tela, este chama o método update(), cuja função é exatamente apagar todas as áreas do desenho com a cor de fundo. Só que, como o código chama o método paint() (responsável por desenhar toda a área de exibição), o método update() não possui utilidade neste caso é só contribui para o aumento da cintilação.

Podemos resolver este inconveniente sobrescrevendo o método update() ou evitando a chamada do método repaint() para redesenhar a tela, passando diretamente para o método paint().
O código seguinte sobrescreve o método update(), eliminando a operação de apagar:

public void update (Graphics g)
{
paint(g);
}

Vale lembrar que esta sobrescrição funciona somente quando o método paint() redesenha toda a área de exibição.
Podemos também não chamar a o método repaint() e passar diretamene a chamar o método paint(). Neste caso, teremos:

Graphics g = getGraphics();
paint(g);

Por hora, ficamos por aqui. Na semana que vem, concluiremos nossa passagem pela parte de multimídia com Java criando um efeito especial de desaparecimento (fading). Um abraço e até lá!