Doble buffer - Animación "Nieve" en java

Iniciado por Maurice_Lupin, 19 Junio 2011, 21:30 PM

0 Miembros y 1 Visitante están viendo este tema.

Maurice_Lupin

La tecnica doble buffer nos permite hacer una animación libre de parpadeos, cuando llamas al método repaint() en un applet, este llama a update() el cual borra toda la pantalla y redibuja llamando al método paint(), esto lo hace directamente en la pantalla, por lo que se nota un feo parpadeo  :-[

Para realizar el Doble Buffer, sobrescribimos el método update(), así relizaremos todo el pintado en una pantalla virtual asi no se visualizara hasta que nosotros volquemos esta pantalla virtual a la pantalla real.

ejemplo
 
Código (java) [Seleccionar]

  Image buffer;
  Graphics pantallaVirtual;
 
 
  //creamos una imagen
  buffer = createImage(Ancho, Alto);

  // creamos la pantalla virtual para el Doble Buffer
  pantallaVirtual = buffer.getGraphics();
 


 
Ahora todo lo que hagamos en la pantallaVirtual se verá reflejado en la imagen buffer, podemos pintar un círculo, rectangulo

o una imagen previamente cargada en la pantallaVirtual.

 
Código (java) [Seleccionar]
public void paint(Graphics g) {        
        g.drawImage(fondo,0,0,this); // dibujamos el fondo
        g.setColor(new Color(240, 240, 255));        
g.drawOval(10,10,200,200);    
   }
 
  public void update(Graphics g) {
       // dibujamos en la pantalla virtual, esto se hace en memoria
       // no se visualizara
       paint(pantallaVirtual);        
       // se vuelca la imagen "buffer" en la pantalla real
       g.drawImage(buffer, 0, 0,640,400, this);          
   }  


Animación nieve: Nevando.java
Código (java) [Seleccionar]

import java.awt.*;
import java.util.Random;
import java.util.Calendar;
import java.applet.Applet;
//Clase Nieve
class Nieve {
   // coordenadas del copo de nieve
   int x, y;
   // indica la dirección
   // derecha = 1 ó izquierda = -1
   int jock;
   //Constructor
   public Nieve(int a, int b, int c) {
       x = a;
       y = b;
       jock = c;
   }
}//fin clase Nieve

// Clase Nevando
public class Nevando extends Applet implements Runnable {
   int Ancho=320, Alto = 200;
   public static final int MAX_COPOS = 250;
   Nieve copo[] = new Nieve[MAX_COPOS];
   // matriz que representa a la pantalla virtual
   // para comprobar la posición de un copo
   int Tabla[][] = new int[Ancho][Alto];
   boolean ok;
   Thread hilo;
   Image buffer, fondo;  
   Graphics pantallaVirtual;
   Random aleat;      
   
   // Constructor
   public Nevando() {        
       try {
           ok = false;
           Calendar ahora = Calendar.getInstance();
           aleat = new Random(ahora.getTime().hashCode());
       }
       catch (Exception ed) {ed.printStackTrace();}                
   }
   
   public void iniciarTabla() {
       // inicializa la matriz con Ceros, porque esta vacia
       for(int j=0; j<Alto; j++)
           for(int i=0; i < Ancho; i++)
               Tabla[i][j] = 0;
   }
   
   // devuelve un numero entre "i" e "f" aletoriamente
   int aleatorio(int i, int f) {
       double random = aleat.nextDouble();
       return ((int)((random*(f-i))+i));
   }
   
   // devuelve 0 si la posicion esta libre
   // si la posicion esta ocupada devuelve 1
   boolean comprobarTabla(int h, int k) {                
       if(h>0 && k>0 && h<Ancho && k<Alto)
           if( Tabla[h][k] == 0) return true;        
       return false;
   }
   
   //metodo init() propio del applet
   public void init() {
       iniciarTabla();
       int k;
       // inicializamos los copos
       for(int j=0; j< MAX_COPOS; j++) {
           k = aleatorio(0,2);
           if(k==0) k = -1;
           // contruimos un nuevo copo
           copo[j] = new Nieve( aleatorio(0,Ancho),aleatorio(0,Alto) , k);
           Tabla[ copo[j].x ][ copo[j].y ] = 1; // representamos el copo en la matriz
       }
       try {
           // cargamos la imagen de fondo
           fondo = getImage(getCodeBase(),"imagenes/fondo.jpg");
           
           //creamos una imagen de 320x200 pixels
           buffer = createImage(Ancho, Alto);
           // creamos la pantalla virtual para el Doble Buffer
           pantallaVirtual = buffer.getGraphics();
           
           //tamaño del Applet 640x400 pixels
           resize(Ancho*2,Alto*2 );
       }
       catch( Exception e ) {System.out.println( e.getMessage()); }
   }
   
   
   public void stop() { hilo = null; }
   
   public void start() {
       if(hilo == null) {
           hilo=new Thread(this);
           hilo.start();
       }
   }
   
   // aquí pintamos todo la animacion
   public void paint(Graphics g) {        
        g.drawImage(fondo,0,0,this); // dibujamos el fondo
        g.setColor(new Color(240, 240, 255));        
        // dibuja la nieve
        for(int i = 0; i < MAX_COPOS; i++) {
            g.fillOval(copo[i].x, copo[i].y, 2, 2);
        }        
   }
   
   // todo lo que hagamos en "pantallaVirtual" se vera reflejado en
   // la imagen "buffer"
   public void update(Graphics g) {
       // dibujamos en la pantalla virtual, esto se hace en memoria
       // no se visualizara
       paint(pantallaVirtual);        
       // se vuelca la imagen "buffer" en la pantalla real
       g.drawImage(buffer, 0, 0,640,400, this);          
   }        
 
// aqui realizamos todo el proceso de animacion  
public void run() {
       while(hilo != null) {
           // la logico de los copos
           for(int i=0; i<MAX_COPOS; i++) {
               // Si el copo aun no llega al suelo lo borramos
               if(copo[i].y < Alto-1)
                   Tabla[copo[i].x][copo[i].y++] = 0;
               
               if(aleatorio(0,2)==0) // si es 0 movemos x
                   copo[i].x += copo[i].jock*(-1);
               
               // Si el copo se sale de la pantalla, se crea uno nuevo
               if((copo[i].x <= 0) || (copo[i].x >= Ancho-1)) {
                   copo[i].x = aleatorio(0,Ancho);
                   copo[i].y = 0;
                   Tabla[copo[i].x][copo[i].y] = 1;
                   copo[i].jock = aleatorio(0,2);
                   if (copo[i].jock == 0) copo[i].jock = -1;
               }
               
               // Si ok=1 significara que el copo aun esta dentro de la pantalla
               ok=((copo[i].x>=0) && (copo[i].x<Ancho) && (copo[i].y>=0) &&(copo[i].y<Alto));
               
               // "Esto es para que el copo caiga si esta en algun objeto"
               // Vemos el punto central                
               if(comprobarTabla( copo[i].x , copo[i].y ) && ok)
                   Tabla[ copo[i].x ][ copo[i].y ] = 1;
               
               // Vemos el punto derecha-abajo
               else if(comprobarTabla(copo[i].x+1, copo[i].y+1) && ok)
                   Tabla[copo[i].x++][copo[i].y++] = 1;
               
               // Vemos el punto izquierda-abajo
               else if(comprobarTabla(copo[i].x-1,copo[i].y+1) && ok)
                   Tabla[copo[i].x--][copo[i].y++] = 1;
               
               // Vemos el punto central-abajo
               else if(comprobarTabla(copo[i].x,copo[i].y+1) && ok)
                   Tabla[copo[i].x][copo[i].y++] = 1;
               
               else // Si no esta en ningun borde, lo dejamos en ese sitio
               {    // y creamos nuevo copo
                   if(ok) {
                       Tabla[copo[i].x][copo[i].y-1] = 1;
                       copo[i].x = aleatorio(0,Ancho);
                       copo[i].y = 0;
                       Tabla[copo[i].x][copo[i].y] = 1;
                       copo[i].jock = aleatorio(0,2);
                       if(copo[i].jock == 0) copo[i].jock = -1;
                   }
               }
               
           }
           repaint(); // llama al metodo Update
           try{hilo.sleep(20);} // para el proceso por 20/1000 segundos
           catch(InterruptedException e){}            
       }
       
   }
}


Aqui el proyecto en Netbeans 5.5 de la animación de nieve en java, tiene comentarios
http://www.mediafire.com/?x69b70m1s74bds3
Un error se comete al equivocarse.

ShotgunLogic

Muy guapo, estaría bien subir unas recopilaciones de chorradas de estas porque se aprenden bastantes cosas!
The clans are marching against the law, bagpipers play the tunes of war, death or glory I will find, rebellion on my mind.

Debci

Cita de: ShotgunLogic en 19 Junio 2011, 23:13 PM
Muy guapo, estaría bien subir unas recopilaciones de chorradas de estas porque se aprenden bastantes cosas!
En todo caso no son chorradas, y menos si como tu dices, aprendes.

Saludos

ShotgunLogic

Cita de: Debci en 20 Junio 2011, 07:51 AM
En todo caso no son chorradas, y menos si como tu dices, aprendes.

Saludos

Joder, era una expresión, ya que al fin y al cabo son complementos y cosillas, madre mía como saltas :¬¬
The clans are marching against the law, bagpipers play the tunes of war, death or glory I will find, rebellion on my mind.

Maurice_Lupin

Algunos más, otros menos lo importante es aprender  ;D
Un error se comete al equivocarse.

Odai

Tengo demasiadas fantasías para ser una ama de casa.
Marilyn Monroe

Maurice_Lupin

Un error se comete al equivocarse.