Cómo optimizar el efecto de visualización en la programación de animación Java
Hay muchas formas de implementar la programación de animación Java, pero el principio básico de su implementación es el mismo, es decir, dibujar una serie de fotogramas en la pantalla para crear la sensación de movimiento. La tecnología de subprocesos múltiples de Java es una tecnología comúnmente utilizada en la programación de animación Java. Desempeña un papel importante en el control del flujo de programas de animación y los efectos de visualización de las animaciones. El parpadeo de la animación y las imágenes incompletas en la programación de animación Java son problemas que los programadores Java encuentran a menudo. Este artículo se basa en el programa de ejemplo de aplicación del autor y explica cómo utilizar técnicas de subprocesos múltiples, actualización sobrecargada, doble almacenamiento en búfer y seguimiento de imágenes para resolver dichos problemas y lograr el mejor efecto de visualización de animación.
Tecnología multiproceso Java
Introducción a la tecnología multiproceso Java
Actualmente, muchos sistemas operativos y sistemas de desarrollo de aplicaciones han adoptado subprocesos. Un hilo es un flujo único de control de un programa y tiene las características de un programa secuencial. Sin embargo, un hilo no es un programa, es solo una secuencia de ejecución del programa. Los subprocesos tienen fuertes capacidades de concurrencia y se pueden ejecutar varios subprocesos al mismo tiempo. Los hilos son dinámicos y tienen un ciclo de vida determinado, pasando por el proceso de creación, ejecución, bloqueo y muerte. Hay dos formas de implementar el soporte del lenguaje Java para la programación multiproceso: una es heredar directamente la clase Thread y la otra es implementar la interfaz Runnable. La clase Thread proporciona métodos de control de subprocesos, como start (), stop (), run (), suspend (), resume () y sleep (), que pueden controlar el estado del subproceso.
Diseño e implementación de hilo de animación
Para actualizar la pantalla varias veces por segundo, se debe crear un hilo para implementar el bucle de animación. Este bucle debe rastrear el fotograma actual y. responder a la actualización periódica de la pantalla requerida. Un error que cometen muchos principiantes de Java es colocar el bucle de animación en paint (), que ocupa el hilo principal de AWT, y el hilo principal será responsable de todo el procesamiento de dibujos y eventos. Por lo tanto, se debe generar un hilo de animación independiente para completar la visualización y actualización de la imagen. Por ejemplo, en un marco de Applet, cuando el Applet se inicia (Inicio), se genera un hilo de animación; cuando el Applet se detiene (detiene), el hilo de animación finaliza para liberar los recursos de CPU que ocupa. El siguiente código de programa (denominado código "C1") es la implementación específica del hilo de animación:
public void start() {
if(animatorThread==null) {
animatorThread=new Thread(this);
//Iniciar hilo de animación
animatorThread.start();
} p>
}
public void stop(){
//Detener hilo de animación
animatorThread=null;
}
Al finalizar el hilo de animación anterior, no llama al método stop() del hilo de animación, sino que establece el hilo de animación en nulo. Porque si llama directamente al método stop() del hilo, obligará al hilo a finalizar todo el trabajo de ejecución, lo que a veces traerá malos resultados. Si el hilo de animación se establece en nulo, en el método run(), el hilo saldrá naturalmente porque no se cumple la condición del bucle. De esta forma se optimiza aún más el programa de animación.
Sobrecarga de actualización() y tecnología de doble almacenamiento en búfer para eliminar el parpadeo
En Java, hay dos razones por las que la animación parpadea: una es porque al mostrar el siguiente cuadro, se llama a The repaint() se llama al método repaint (), se debe borrar todo el fondo y luego se llama al método paint () para mostrar la pantalla. De esta manera, el parpadeo es lo que el usuario ve durante el breve intervalo entre borrar el fondo y dibujar la imagen. La otra es que debido a que el método paint() requiere cálculos complejos, se necesita demasiado tiempo para dibujar cada cuadro y los valores de cada píxel en la imagen no se pueden obtener al mismo tiempo, lo que hace que la frecuencia de generación de la animación sea menor que la frecuencia de actualización de la pantalla, provocando parpadeos.
Los dos métodos siguientes pueden eliminar o reducir significativamente el parpadeo.
Sobrecarga del método update()
Cuando AWT recibe una solicitud de redibujo de un Applet, llama al método update() del Applet. De forma predeterminada, el método update() borra el fondo del subprograma y luego llama al método paint(). La sobrecarga del método update() puede incluir el código de dibujo previamente en el método paint() en el método update(), evitando así borrar toda el área cada vez que se vuelve a dibujar. Dado que el fondo ya no se borra automáticamente, los programadores de Java deben hacerlo ellos mismos en update().
Tecnología de doble búfer
Otra forma de eliminar el parpadeo entre fotogramas es utilizar la tecnología de doble búfer, que se utiliza en muchos subprogramas animados. El principio fundamental es crear una imagen de fondo, dibujar cada cuadro en la imagen y luego llamar al método drawImage() para dibujar toda la imagen de fondo en la pantalla a la vez. La ventaja de este enfoque es que la mayor parte del dibujo está fuera de la pantalla. Dibujar una imagen fuera de la pantalla en la pantalla de una sola vez es mucho más eficiente que dibujar directamente en la pantalla. Antes de crear una imagen de fondo, primero debe generar un búfer de fondo adecuado llamando al método createImage () y luego obtener el entorno para dibujar en el búfer (es decir, el objeto de clase Gráficos).
El siguiente código de programa de ejemplo (denominado código "C2") es una combinación de estos dos métodos. La tecnología de doble almacenamiento en búfer se implementa en el método de actualización() sobrecargado. Entre ellos, offImage es un objeto de la clase Image y offGraphics es un objeto de la clase Graphics. Estos dos objetos de clase son la clave para implementar la tecnología de doble búfer. El código relevante es el siguiente:
public void paint(Graphics g){
update(g);
}
public void update( Graphics g){
Dimensión d=getSize();
//Si la imagen de fondo no existe, crea una imagen de fondo
si ((offGraphics= =null)||(d.width!=offDimension.width)
||(d.height!=offDimension.height)) {
offDimension=d ;
offImage=createImage(d.width,d.height);
offGraphics=offImage.getGraphics();
}
//wipe Excepto el fotograma anterior
offGraphics.setColor(getBackground());
offGraphics.fillRect(0,0,d.width,d.height); p>
offGraphics.setColor(Color.black);
//Envía el fotograma actual a la imagen especificada
for(int i=0; i<10; i++ ){
offGraphics.drawImage(images[i],frameNumber*5%(d.width/2)
,i*d.height/10,this); p>
}
// Genera la imagen de fondo especificada
g.drawImage(offImage,frameNumber*5%(d.width/2),0,this); p>
}
La tecnología de doble búfer puede hacer que la animación sea fluida, pero tiene la desventaja de que es necesario asignar un búfer para la imagen de fondo. ocupan una gran parte de la memoria.
Seguimiento de imágenes y mejora gradual del programa
Seguimiento de imágenes
Cuando el hilo de animación recién comenzó, debido a que no se cargaron todas las imágenes, la imagen que se muestra en el Pantalla A menudo mutilada. En este momento, puede utilizar objetos de clase MediaTracker o ImageOberver para el seguimiento de imágenes. Una vez cargadas todas las imágenes, llame al método drawImage() para mostrar la imagen en la pantalla. El cuarto parámetro del método DrawImage() es el objeto de clase ImageObserver, por lo que puede utilizar el objeto de clase ImageObserver para el seguimiento de imágenes. Implementar el seguimiento de imágenes en el método init () del programa Applet de la aplicación real es equivalente a dibujar la imagen una vez antes de llamar al método DrawImage () del hilo de animación, porque el proceso de inicialización del hilo de animación, es decir, el init ( ) el método se llama primero. El siguiente código (denominado código "C3") muestra que el método init() utiliza el objeto de clase MediaTracker para cargar la imagen de seguimiento. El código es el siguiente:
public void init(){<. /p>
tracker=nuevo MidiaTracker(este);
for(int i=1;i<=10;i++){
imagen[i-1]= getImage(getCodeBase(), "image"+i+".gif");
//Utiliza el método addImage() del objeto de clase MediaTracker para realizar un seguimiento de la carga de imágenes
tracker.addImage(imágenes[i-1 ],0);
}
......
}
Mejora adicional del programa
Agregue la siguiente declaración if al método update() sobrecargado del código "C2" para juzgar el método de seguimiento de imágenes del objeto de clase MediaTracker. La declaración if es como. sigue:
if(!tracker.checkAll ()){
//Si la imagen no se ha cargado, solo se borra el fondo y se genera un estado.
g.clearRect(0,0,d.width,d. height);
g.drawString("Por favor, espere...",0,d.height/2);
return;
} p>
Agregue dos líneas de código al método stop() del código "C1" para liberar los recursos de memoria ocupados por la tecnología de doble búfer En este momento, el método stop() se cambia a:
public void stop(){
//Detener el hilo de animación
animatorThread=null. ;
//Liberar recursos de memoria para doble buffer
offGraphics=null;
offImage=null;
}
En este punto de la modificación del programa, todavía hay un pequeño problema, es decir, después de que se inicia el hilo de animación, la primera imagen a veces todavía tiene rastros residuales, en lugar de borrarse por completo cuando se actualiza la imagen. Si desea resolver este problema, simplemente cambie el último bucle for() y el método g.drawImage() en el código "C2" al siguiente código.
for(int i=0;i<10;i++){
offGraphics.drawImage(images[frameNumber%10],
,frameNumber*5 %(d.width),i*d.height/10,this);
}
g.drawImage(offImage,0,0,this);
Mantenga una velocidad de fotogramas constante
Para que los usuarios vean animaciones sin parpadear, se requiere una velocidad de al menos 12 fotogramas por segundo. Las velocidades de fotogramas más altas producen animaciones más fluidas.
Por lo general, entre cada dos fotogramas de visualización de la animación, se llama al método sleep() del hilo para que duerma durante un período fijo