lunes, 7 de enero de 2013

Graficos en Java, la técnica DobleBuffering

Increíble casi hace 2 años de la ultima entrada... de hecho probablemente cuando la publique ya serán 2 años... pero bueno... espero perdonen mi lentitud, cada día uno sabe mas cosas... y no las comparte que egoísta "la gente" :P jajaja.

Bueno esta vez explicare algo relativamente sencillo, como utilizar doble buffer en java, se que existen cientos de lugares, donde explican esto, pero a mi parecer lo explican de una forma muy compleja, cuando en realidad es algo muy sencillo y util en la mayoría de los casos.

Antes de pasar al código... deberías tener un conocimiento básico de como utilizar gráficos en java... es decir saber dibujar una figura, una cadena, o una imagen algo asi... el problema que trato de exponer es cuando intentas hacer que  lo que sea que dibujas "se mueva", para hacer que una imagen "se mueva" a través de la pantalla se requiere reemplazar la figura con otra parecida en una ubicación diferente en la pantalla, pero al intentarlo solo sabiendo utilizar el método paint() de la clase Canvas te das cuenta que "parpadea", "flashea".

Ej. supongamos que queremos que un personaje camine, tenemos imágenes de un sprite sheet... programamos y llegamos al punto en el que tenemos una imagen algo asi:


Esto pasa porque la clase Canvas cuenta con un método llamado update, el cual borra completamente la pantalla en ciertas ocasiones, y es el culpable de dicho parpadeo... en realidad si tu metodo paint() borra la imagen anterior, no es necesario que update borre la imagen completa, este detalle se corrige sobreescribiendo update con tu codigo de paint() y haciendo que paint llame a update() asi:

    ...
    @Override
    public void update(Graphics g){
        //el codigo que tenias en paint tal cual
    }
    
    @Override
    public void paint(Graphics g){
        update(g);//se llama al metodo update
    }
    ... 
 
 
Pero aun así obtendríamos una imagen que sigue  parpadeando aparentemente menos, pero continua...esto es porque nosotros mismos borramos la imagen antes de dibujar la siguiente, o al menos eso deberíamos hacer..., por lo tanto en cierto momento la pantalla esta vacía... se utiliza la técnica DobleBuffering la cual consiste en solo dibujar imagenes completas en pantalla, esto es mas fácil de explicar con imagenes, la imagen de abajo muestra como funcionaria el código sin usar DobleBuffering:



Doble buffering consiste realizar los cálculos y dibujar las figuras en memoria antes de mostrarlos al usuario la siguiente imagen muestra de forma mas gráfica doble buffering



Utilizar esta técnica es relativamente sencillo solo debemos agregar dos nuevos atributos en nuestra clase Canvas una imagen y un objeto Graphics, y en el constructor inicializamos estos atributos creando un nuevo objeto BufferedImage y obteniendo su objeto Graphics con el método getGraphics() ahora en nuestro método update en lugar de utilizar el parámetro Graphics utilizaremos el objeto Graphics de nuestra imagen que esta en memoria y al final solo dibujaremos la imagen de la memoria la cual ya fue completamente renderizada, podemos verlo mejor en el siguiente fragmento de código

public class MiCanvas extends Canvas{
    public static final int _WIDTH;
    public static final int _HEIGHT;
    private BufferedImage imagenBuffer;
    private Graphics g_imagenBuffer;
 
    public MiCanvas(){
        this.setSize(_WIDTH, _HEIGHT);
        //creamos la imagen en memoria
        imagenBuffer = new BufferedImage(_WIDTH,
                          _HEIGHT
                          BufferedImage.TYPE_INT_RGB
                      );
        //obtenemos los graficos
        g_imagenBuffer = imagenBuffer.getGraphics();
    }
    
    @Override
    public void update(Graphics g){
       //realizamos nuestros calculos 
       //pero ahora utilizando g_imagenBuffer en lugar de g
       //y por ultimo imprimimos la imagen que tenemos en  memoria
       g.drawImage( imagenBuffer, 0, 0, this );
    }
    ... 

Después de haber realizado los cambios, nuestro personaje caminará mas fluido como se muestra en esta imagen:
Pero no le crean a los las imágenes gif, pueden hacer la prueba ustedes mismos yo igual dejo el código del Megaman donde se puede ver el uso del DobleBuffering lo cual es una técnica sencilla, pero muy útil.

liga para descargar el código fuente del proyecto de NetBeans Megaman:
Proyecto de NetBeans "Megaman"

Si llegaste hasta este párrafo... ¡¡¡Muchas gracias por leer mi blog!!! un entrada cada 2 años... difícil tener fans jajaja ;) hasta la próxima esperemos que sea menos de 2 años.