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!