viernes, 17 de abril de 2009

Animacion

Otro de los temas basicos y mas importantes es la animacion, esto como muchos sabran consiste en cambiar la imagen original de lugar o forma de a pasos, asi da un efecto fluido de movimiento.
En computacion hay un problema ciertamente cuando hacemos eso, si solo nos disponemos a hacer una animacion, y mostrar una imagen despues de otra, por ponerlo simple, maquinas mas potentes lo haran mas rapido que otras menos potentes, ademas, hay veces que queremos que se tome su tiempo para ciertas cosas, poreso esta seccion de animacion va muy entrelazada con Timers.
Timers son por llamarlo asi objetos que nos permiten repetir algo, cada cierto periodo de tiempo.
Los timers que usare en este Knol son muy limitados, de hecho solo usare el timer de swing, pero hay mas, hay uno integrado a Java, y otra forma es usando Threads, y no se si habra mas, no se mucho de Java, de todas formas, aunque no sea el mas eficiente de todos, es el que usaremos por ser el mas simple, las diferencias con respecto a los otros no son muchas, y si logro terminar esto bien, pondre como anexo las otras formas de timers.

Muy bien, vamos a animar, la meta en esta seccion sera mover una imagen cualquiera, a lo largo de nuestra ventana, para esto, modificare las clases que teniamos hasta ahora, asi que si no viste la seccion anterior, te recomiendo ver el codigo completo que esta mostrado al final.
Nosotros ya teniamos la ventana y una imagen, la imagen esta es muy grande para animar, asi que voy a usar una mas pequeña, lo unico que hare es cambiar el archivo "imagen.png" de una imagen de 300x300 a la de una de 30x30.
La clase Main, no sufre cambios esta vez, todos los cambios seran en la clase Board. Es importante entender que es Board, imaginalo como lo que es la ventana, menos los bordes, el menu, etc, todo lo que esta "blanco" por asi decirlo. Por eso es que todos los cambios son ahi, porque la ventana sige siendo de 300x300.
Si quieren pueden cambiarle el titulo, lo dejo a su criterio.

Comenzamos a modificar, importo una nueva clase de awt, Color. Esta clase te permite elejir colores mas facilmente, solo eso, accedes a los colores como "Color.white", por ejemplo.
Ahora vamos a importar las cosas que vamos a usar para el timer, en este caso el de swing, para esto necesitamos estas clases/estructuras.

import java.awt.Toolkit;
import javax.swing.Timer;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent; // Para poder usar actionPerformed, necesitamos este tipo


Toolkit lo usamos para forzar una sincronizacion con el timer, Timer es el timer en si, ActionListener es una estructura, la cual es necesaria para usar el timer, solo tiene una funcion, la funcion actionListener, que tiene como argumento un ActionEvent, poreso lo importamos, necesitamos ese tipo de datos.
La idea de esta animacion sera simplemente una imagen de 30x30 rebotando por la pantalla. Para eso es importante saber el concepto en si, vamos a necesitar una imagen, y la posicion de la imagen, la cual ira cambiando, por lo tanto es dinamica, si cambia tambien tiene que tener una velocidad a la que cambia, en este caso sera constante, y no cambiara. Hagamos estas variables globales.

private Timer timer;
private int x, y, dx, dy;
private static int SPEED = 2;


dx y dy (o como los leo yo, delta x y delta y) seria la aceleracion de la imagen. A mi tampoco me gusta Fisica, y no la tengo como materia para Cincias de la Computacin, asi que siendo feliz en mi ignorancia, voy a usar esa palabra refiriendome a eso, perdonen si esta mal, en fin, esas variables son simplemente para sumarle a x, asi saber para donde va y a que velocidad.
Vamos al constructor de Board, agegamos esto al final del todo

this.setBackground(Color.white);
x = 150;
y = 10;
dx = dy = SPEED;

// Timer
timer = new Timer(5, this); // cada 5ms llama actionPerformed
timer.start();


Primero, cambiamos el color a blanco, para eso importamos la clase Color, solo para acceder al color mas facilmente, luego damos valores cualquiera para x e y, y ponemos a dx y dy iguales a la velocidad que es constante (dy y dx no son constantes ya que cambiaran de sentido).
Vamos al metodo paint, y agregamos esto antes del dispose

Toolkit.getDefaultToolkit().sync(); // fuerza sincronizacion, basicamente


Bastante explicado esta, la documentacion lo explica como "Synchronizes this toolkit's graphics state. Some window systems may do buffering of graphics events[...]".

Finalmente agregamos esta funcion, que es la que el timer llama cada 5 millisegundos, en ella hacemos la logica y hacemos que actualize lo que dibujamos.

public void actionPerformed(ActionEvent e){ // Se ejecuta cada 5ms
x+=dx;
y+=dy;
if(x > 300-image.getWidth(null) || x < 0)
dx *= -1;
if(y > 300-image.getHeight(null) || y < 0)
dy *= -1;
repaint(); // "re-pintamos" el panel
}


En ella sumamos a x dx y a y dy, si x se escapa de la pantalla, invertimos dx, para que cambie su sentido horizontal, eso da el efecto de rebote, lo mismo hacemos con el y, y finalmente, "re-pintamos" el panel. Esa funcion la hereadmos cuando heredamos JPanel.
Aca esta la clase Board completa.

package animation;

import java.awt.Image;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
import javax.swing.ImageIcon;
import java.awt.Color;

// Timer Imports
import java.awt.Toolkit;
import javax.swing.Timer;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent; // Para poder usar actionPerformed, necesitamos este tipo

/**
*
* @author fede
*/
public class Board extends JPanel implements ActionListener {
private Image image;
private Timer timer;
private int x, y, dx, dy;
private static int SPEED = 2;

public Board(){
ImageIcon ii = new ImageIcon(this.getClass().getResource("image.png"));
image = ii.getImage();
this.setBackground(Color.white);
x = 150;
y = 10;
dx = dy = SPEED;

// Timer
timer = new Timer(5, this); // cada 5ms llama actionPerformed
timer.start();
}

public void paint(Graphics g){
super.paint(g);

Graphics2D g2d = (Graphics2D)g; // Convertimos a g de Graphics a Graphics2D
g2d.drawImage(image, x, y, this);

// Timer
Toolkit.getDefaultToolkit().sync(); // fuerza sincronizacion, basicamente

g.dispose();
}

public void actionPerformed(ActionEvent e){ // Se ejecuta cada 5ms
x+=dx;
y+=dy;
if(x > 300-image.getWidth(null) || x < 0)
dx *= -1;
if(y > 300-image.getHeight(null) || y < 0)
dy *= -1;
repaint(); // "re-pintamos" el panel
}
}


Si todo sale bien, al correr Main.java, deberian ver una pequeña imagen 30x30 (la cual ustedes deben de poner ahi, cualquier imagen) rebotar en la ventana.



Repito que hay otros Timers, pero solo use el de swing.
Descargar codigo fuente: de 4shared

4 comentarios:

  1. Exelente informacion me ayudo mucho con mi trabajo
    era exactamente lo que buscaba
    GRACIAS AMIGO

    ResponderEliminar
  2. Wow, y mira que he buscado por multitud de sitios, pero tu has sido quien me ha ayudado de verdad. Como te dijo el otro chico,

    UN MILLON DE GRACIAS

    Saludos, y te prometo que revisare todos tus post. =]

    ResponderEliminar
  3. hola oye ya no esta tu código, ya fue removido si lo puedes subir otra vez por favor, es lo que andaba buscando para poder mover la imagen, solo que copie el código que esta en tu blog pero no aparece la imagen ya le puse una y nada hubieras puesto también la clase principal

    ResponderEliminar
  4. En verdad miles de agradecimientos bro!!! He buscadpo y buscado y tú has sido la unica persona que sabe documentar bien :)

    ResponderEliminar