En esta entrada del blog,
voy a enseñarte cómo hacer imágenes con animación en Java. Para
ello, lo primero que vamos a necesitar son...lo has adivinado:
imágenes. Pueden ser fotos, o pueden ser dibujos sencillos, pero eso
sí, tienen que mostrar movimientos consecutivos; por ejemplo, un
pájaro subiendo y bajando las alas, o una cara abriendo y cerrando
los ojos.
Si sabes utilizar
Photoshop, Gimp o cualquier otro programa por el estilo, enhorabuena,
dale rienda suelta a tu imaginación para crear las imágenes que
desees (y ya puestos, compártelas con nosotros).
Si por el contrario, eres
como yo, que a lo más que llegas es a dibujar un círculo con Paint,
pues nada, le pones dos circulitos más pequeños dentro para simular
ojos abiertos y dos líneas para simular ojos cerrados y ya tienes
una carita que parpadea. Ahora guardas los dos dibujos como .png y
listo.
También puedes añadirle
una imagen de fondo que ocupe toda la pantalla: una foto en formato
.jpg, otro dibujo o un fondo liso, lo que quieras.
Lo que vamos a hacer con
estas imágenes es, primero, crear un ArrayList para contenerlas, y
después, asignarles a cada una una duración determinada en
milisegundos. Por último, vamos a mostrarlas en pantalla en un bucle
para conseguir ese efecto de animación.
Para ello vamos a crear
una clase, Animación (qué sorpresa de nombre, ¿eh?) que contendrá
los métodos necesarios. Despues haremos otra para probarla, y
originales como somos la llamaremos AnimaciónTest.
PruebaDeAnimación tampoco está mal, pero es que es más largo. Dentro de esta clase AnimaciónTest vamos a utilizar un objeto de la clase PantallaCompleta, que creamos en una entrada anterior y que utilizamos, nunca lo adivinarías, para visualizar el resultado en una pantalla completa . Aquí puedes ver el código de esa clase.
Para que luego no te líes
con el código, te voy a explicar el significado de algunas variables
que verás en él:
- frames, que en inglés viene siendo fotogramas, es el nombre del ArrayList
- actualFrame es el número de índice de un elemento de frames
- tiempoAnimación es el tiempo que dura toda la animación
- tiempoTotal es la suma de los milisegundos de duración que hemos asignado a cada imagen
Clase Animación.java
import java.awt.Image;
import java.util.ArrayList;
public class Animación{
private ArrayList frames;
private int actualFrame;
private long tiempoAnimación;
private long tiempoTotal;
public Animación(){
frames = new ArrayList();
tiempoTotal = 0;
start();
}
public synchronized void addFrame(Image image, long duración){
tiempoTotal += duración;
frames.add(new AnimFrame(image, tiempoTotal));
}
public synchronized void start(){
tiempoAnimación = 0;
actualFrame = 0;
}
public synchronized void update(long tiempoTranscurrido){
if(frames.size()>1){
tiempoAnimación += tiempoTranscurrido;
if(tiempoAnimación >= tiempoTotal){
tiempoAnimación = tiempoAnimación % tiempoTotal;
actualFrame = 0;
}
while(tiempoAnimación > getFrame(actualFrame).endTime){
actualFrame++;
}
}
}
public synchronized Image getImage(){
if (frames.size() ==0){
return null;
}else{
return getFrame(actualFrame).image;
}
}
private AnimFrame getFrame(int i){
return (AnimFrame)frames.get(i);
}
private class AnimFrame{
Image image;
long endTime;
public AnimFrame(Image image, long endTime){
this.image = image;
this.endTime = endTime;
}
}
}
Clase AnimaciónTest.java
import java.awt.*;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
public class AnimaciónTest {
public static void main(String args[]) {
DisplayMode displayMode= new DisplayMode(1024, 768, 32,
DisplayMode.REFRESH_RATE_UNKNOWN);
AnimaciónTest test = new AnimaciónTest();
test.run(displayMode);
}
private static final long DEMO_TIME = 10000;
private PantallaCompleta pc;
private Image bgImage;
private Animación animación;
public void loadImages() {
// cargamos las imágenes
bgImage = loadImage("images/background.jpg");
Image cara1 = loadImage("images/cara1.png");
Image cara2 = loadImage("images/cara2.png");
Image cara3 = loadImage("images/cara3.png");
// creamos la animación
animación = new Animación();
animación.addFrame(cara1, 250);
animación.addFrame(cara2, 150);
animación.addFrame(cara1, 150);
animación.addFrame(cara2, 150);
animación.addFrame(cara3, 200);
animación.addFrame(cara2, 150);
}
private Image loadImage(String fileName) {
return new ImageIcon(fileName).getImage();
}
public void run(DisplayMode displayMode) {
pc = new PantallaCompleta();
try {
pc.setFullScreen(displayMode, new JFrame());
loadImages();
animationLoop();
}
finally {
pc.restoreScreen();
}
}
public void animationLoop() {
long tiempoInicio = System.currentTimeMillis();
long tiempoActual = tiempoInicio;
while (tiempoActual - tiempoInicio < DEMO_TIME) {
long tiempoTranscurrido =
System.currentTimeMillis() - tiempoActual;
tiempoActual += tiempoTranscurrido;
// actualizamos la animación
animación.update(tiempoTranscurrido);
// se dibuja en pantalla
Graphics g =
pc.getFullScreenWindow().getGraphics();
draw(g);
g.dispose();
// una pequeña pausa
try {
Thread.sleep(20);
}
catch (InterruptedException ex) { }
}
}
public void draw(Graphics g) {
// se dibuja el fondo
g.drawImage(bgImage, 0, 0, null);
// se dibuja la imagen y la centramos más o menos
g.drawImage(animación.getImage(), 300, 200, null);
}
}
Yo he utilizado una imagen de fondo y tres dibujos de una cara, pero tú puedes usar el número de imágenes que quieras. Fíjate que cada imagen se puede añadir más de una vez, en distinto orden y con distinto tiempo asignado, para crear distintas animaciones. Tú puedes jugar con ello hasta encontrar la que te gusta.
En otro momento te enseñaré a añadirle otros efectos y a utilizar la clase BufferStrategy para evitar que la imagen parpadee.
¡Si tienes alguna duda, ya sabes dónde estoy!