Programación de juegos Java 2D: diferentes enfoques para hacer un bucle de juego


10

Soy nuevo en la programación de juegos Java, pero cuanto más leo, más me confundo, porque he visto varios enfoques diferentes para hacer un bucle de juego: 1. El enfoque estándar, que usa la clase Timer (parece ser menos preciso). 2. El enfoque más preciso que utiliza System.nanoTime. 3. Un enfoque simple que utiliza scheduleAtFixedRate.

¿Cuál debería preferirse en general y dónde están las ventajas / desventajas de cada enfoque? Gracias de antemano por cualquier información.

Respuestas:


7

Para un bucle de juego básico, ejecutaría un bucle while, dentro del cual obtendría el tiempo usando nanoTime (), determinaría cuánto tiempo ha pasado desde el último fotograma, luego actualizará su estado de juego y renderizará.

Usando http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/System.html#nanoTime%28%29 , puede sondear el tiempo transcurrido. Básicamente...

public static void main(String [ ] args)
{
    long current_frame_time = system.nanoTime();
    long last_frame_time = current_frame_time;

    while(gameIsRunning)
    {
        last_frame_time = current_frame_time;
        current_frame_time = system.nanoTime();

        long timeTaken = current_frame_time - last_frame_time;

        //update and render game here
    }
}

Este método básico se puede mejorar, por ejemplo, http://www.koonsolo.com/news/dewitters-gameloop/ y http://gafferongames.com/game-physics/fix-your-timestep/ .

Alternativamente, puede crear un temporizador y configurarlo para ejecutar su actualización y renderizar cada X milisegundos. Pero, hay algunos inconvenientes para construir un gameloop como ese.

De acuerdo con http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Timer.html : " Corresponde a cada objeto Timer un hilo de fondo único que se utiliza para ejecutar todos los temporizadores tareas, secuencialmente. Las tareas del temporizador deben completarse rápidamente. Si una tarea del temporizador tarda un tiempo excesivo en completarse, "acapara" el hilo de ejecución de tareas del temporizador. Esto puede, a su vez, retrasar la ejecución de tareas posteriores, que pueden "agruparse" y ejecutar en rápida sucesión cuando (y si) la tarea ofensiva finalmente se complete " .

De acuerdo con http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Timer.html#scheduleAtFixedRate%28java.util.TimerTask,%20java.util.Date,%20long%29 : " En la ejecución de tasa fija, cada ejecución se programa en relación con el tiempo de ejecución programado de la ejecución inicial. Si una ejecución se retrasa por cualquier motivo (como la recolección de basura u otra actividad en segundo plano), dos o más ejecuciones ocurrirán en rápida sucesión "ponerse al día". A la larga, la frecuencia de ejecución será exactamente la recíproca del período especificado (suponiendo que el reloj del sistema subyacente Object.wait (largo) sea exacto) " .

Como generalmente no sabes de antemano cuánto tiempo lleva un bucle de juego, configurar un temporizador para ejecutar tu bucle de juego cada X milisegundos (dependiendo de la velocidad de fotogramas objetivo) podría generar algunos fotogramas agrupados, que se ejecutarían cada vez que un fotograma es terminado en lugar de cuando se programa un marco. Cuando eso sucede ... ¿por qué usar un temporizador en primer lugar?

Ahora, no me malinterpreten, el temporizador no es una mala clase, pero por lo general es más adecuado para pequeñas tareas que deben realizarse periódicamente o en un momento determinado, por ejemplo, un cliente de correo puede querer comprobar si hay correo nuevo cada 5 minutos, o un contador puede disminuir cada segundo para mostrar una cuenta regresiva antes del comienzo de una carrera.


La pregunta era sobre los bucles del juego, por lo que la información awt / swing está fuera de tema. Sin embargo, parecía que esa información era relevante debido a una línea irrelevante y confusa en la pregunta, así que eliminé eso.
jhocking

Adapte mi respuesta para reflejar los cambios hechos a la pregunta.
Exilyth

7

No pondría el bucle principal en un temporizador. Más bien, haría un ciclo 'while' que procesa cada cuadro y luego usaría algún tipo de funcionalidad de cronometraje (suena como en Java que sería System.nanoTime) para calcular cuánto tiempo ha pasado desde el último cuadro / última iteración del lazo.

Ciertos lenguajes son excepciones aquí (p. Ej., JavaScript, ActionScript) porque esos lenguajes operan dentro de un entorno que tiene un bucle principal implícito para engancharse (p. Ej., El navegador, Flash Player) pero esa excepción no se aplica a Java.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.