Entradas

Pausa y Reanudación de un juego. Java Game 8

Incluso, en el juego más emocionante, llega un momento en que el usuario quiere pausar y reanudar más adelante. La documentación de Java para la clase Thread recomienda utilizar wait() y notify() para implementar la pausa y reanudar la funcionalidad. La idea es suspender la animación, pero el hilo del distribuidor de eventos aún responderá a la actividad del GUI (escritorio). Para implementar este enfoque, se puede introducir un booleano isPaused, que se establece en true vía el método pauseGame(): // global variable private volatile boolean isPaused = false; public void pauseGame( ){ isPaused = true; } private void testPress(int x, int y){ // is (x,y) important to the game? if (!isPaused && !gameOver) { // ... } } private void gameUpdate( ){ if (!isPaused && !gameOver) // update game state ... } public synchronized void resumeGame( ){ isPaused = false; notify( ); } public synchronized void stopGame( ){ running = false; ...

FPS y UPS. Aumento de la velocidad del juego. Java Game 7

Si un juego ofrece 50 FPS (es decir, 50 iteraciones run() de animación por segundo), al agregar un nuevo gameUpdate() dentro de run() estará haciendo 100 actualizaciones por segundo, es decir el doble. Este tipo de medición, aparte del FPS, es la denominada  UPS. Este estilo de codificación hace que el juego avance más rápidamente, ya que el estado del juego está cambiando dos veces más rápido, pero a costa de saltarse la representación de esos estados adicionales. Sin embargo, esto puede no ser notable, especialmente si el valor FPS es 20 o superior. public void run( ){ //... running = true; while(running) { gameUpdate( ); // game state is updated gameUpdate( ); // game state is updated again gameRender( ); // render to a buffer paintScreen( ); // paint with the buffer // sleep a bit } System.exit(0); } // end of run( ) Una limitación en las altas tasas de FPS es la cantidad ...

Timer Resolution - Contador temporal de resolución. Java Game 6

El Timer Resolution o contador de resolución  en un juego es el tiempo mínimo que tarda en sucederse una imagen en pantalla para que parezca continua en el ojo humano. Por ejemplo, diff nos calula la diferencia de tiempo reciente en milisegundos tomando como referencia que t1 y t2 nos pueden medir la diferencia de tiempo en el que se realiza un bucle run() para un juego.                 long t1 = System.currentTimeMillis ();                long t2 = System.currentTimeMillis ();                long diff = t2 - t1; // en ms currentTimeMillis() nos da el valor de resolución en milisegundos, que desafortunadamente depende del sistema operativo. En Windows 95 y 98 la resolución es de 55 ms, lo que significa que las llamadas a currentTimeMillis() sólo devolverán valores diferentes aproximadamente cada 55 ms. En el bucle de animación run(), el efec...

FPS y Sleep. Java Game 5

Una debilidad del bucle de animación run() es que su velocidad de ejecución no está restringida para todos los PC. En una máquina lenta su bucle puede ser 20 veces por segundo, en cambio con el mismo código en una máquina rápida puede ser de 80 veces, haciendo que el juego progrese cuatro veces más rápido y tal vez haciendolo injugable. La velocidad de ejecución del bucle debe ser aproximadamente la misma en todas las plataformas, por ello existe una medida popular  llamada frames por segundo (FPS), que controla la velocidad a la que avanza la animación. Para una clase GamePanel , una trama corresponde a un solo paso a través de la función update-render-sleep dentro del bucle run(). Por lo tanto, los 100 FPS deseados implican que cada iteración del bucle debe tomar 1000/100 == 10 ms. Este tiempo de iteración se almacena en la variable de período sleep() y da el tiempo de reposo requerido para mantener el FPS deseado. Por ejemplo, 100 FPS significan un período de 10 ms, y si los ...

Renderizado y repaint(). Java Game 4

A continuación vamos a analizar la llamada a repaint() dentro del bucle run() : while(running) { gameUpdate( ); // game state is updated gameRender( ); // render to a buffer repaint( ); // paint with the buffer try { Thread.sleep(20); // sleep a bit } catch(InterruptedException ex){} } El método repaint() no es un método exacto a la hora de pintar en pantalla ya que depende de la JVM, el tiempo de procesamiento para la renderización no es exacto, así que podemos utilizar otra forma de hacerlo incorporando manualmente el método paintScreen(): public void run( ) /* Repeatedly update, render, sleep */ { running = true; while(running) { gameUpdate( ); // estado del juego actualizado gameRender( ); // render a un buffer paintScreen( ); // dibuja buffer en pantalla try { Thread.sleep(20); // sleep un poco } catch(InterruptedException ex){} } System.exit(0); } // Fin de run( ) private void paintScreen( ) // activa el buffer de imagen renderizada a pantalla { Graph...

Interacción con el Usuario. Java Game 3

Cuando un juego ocupa la pantalla completa lo unico que nos interesa es la interacción con el usuario, en este caso la interacción viene dada a través del ratón (Mouse). Por lo que el constructor de nuestro juego con nombre de clase GamePanel recoge los clics del ratón y nos dice la posición X e Y de éste:   public GamePanel( ) { setBackground(Color.white); setPreferredSize( new Dimension(PWIDTH, PHEIGHT)); setFocusable(true); requestFocus( ); // JPanel recibe eventos de clics readyForTermination( ); // crea componentes del juego // ... // escucha los clics en el raton addMouseListener( new MouseAdapter( ) { public void mousePressed(MouseEvent e) { testPress(e.getX( ), e.getY( )); } }); } private void readyForTermination( ) { addKeyListener( new KeyAdapter( ) { // listen for esc, q, end, ctrl-c public void keyPressed(KeyEvent e) { int keyCode = e.getKeyCode( ); if ((keyCode == KeyEvent.VK_ESCAPE) || (keyCode == KeyEvent.VK_Q) || (keyCode == KeyEvent.VK_END) ...

Dibujar un objeto en una imagen de fondo - Java Game 2

Esta técnica se conoce como doble buffer. Las operaciones necesarias para la renderización no se aplican directamente a la pantalla sino a una imagen. La imagen se coloca en la pantalla mediante paintComponent() como resultado del repaint(). public void paintComponent (Graphics g) {  super.paintComponent (g);  if (dbImage! = null)  g.drawImage (dbImage, 0, 0, null); } La ventaja principal de la doble memoria intermedia es reducir el parpadeo en pantalla.  La llamada a drawImage () en paintComponent () es rápida, suficiente para que el cambio de un marco a otro sea percibido como instantáneo. Ejemplo: public class GamePanel2 extends JPanel implements Runnable{ //Definición de variables antes del Constructor private static final int PWIDTH = 500; //variable ancho del juego private static final int PHEIGHT = 400; private int x = 15; private int y = 15; private Thread animator; // variable hilo private volatile boolean running = f...