sábado, 24 de noviembre de 2012

Animación de Imágenes en Java

votar

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!

1 comentario:

  1. como hago que no parpadee una imagen por ejemplo este es mi codigo en java
    private void render(){
    Graphics g;
    g=this.getGraphics();
    if(g!=null){
    g.setcolor(Color.black);
    g.fillrect(0, 0, 400, 400);
    g.drawImage(imagen.getImage(), x, y, 40, 40, null);
    Toolkit.getDefaultToolkit().sync();
    g.dspose();
    }}

    ResponderEliminar