Java 2D-Spielprogrammierung: Verschiedene Ansätze zum Erstellen einer Spielschleife

10

Ich bin neu in der Java-Spielprogrammierung, aber je mehr ich lese, desto verwirrter bin ich, weil ich verschiedene Ansätze gesehen habe, um eine Spieleschleife zu erstellen: 1. Der Standardansatz, der die Timer-Klasse verwendet (scheint weniger zu sein präzise). 2. Der genauere Ansatz, der System.nanoTime verwendet. 3. Ein einfacher Ansatz, der ScheduleAtFixedRate verwendet.

Welches sollte generell bevorzugt werden und wo liegen die Vor- und Nachteile jedes Ansatzes? Vielen Dank im Voraus für jede Info.

user1812379
quelle

Antworten:

7

Für eine einfache Spielschleife würden Sie eine while-Schleife ausführen, in der Sie mit nanoTime () die Zeit abrufen, bestimmen, wie viel Zeit seit dem letzten Frame vergangen ist, und dann Ihren Spielstatus aktualisieren und rendern.

Mit http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/System.html#nanoTime%28%29 können Sie die verstrichene Zeit abfragen. Grundsätzlich...

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
    }
}

Diese grundlegende Methode kann verbessert werden, z . B. http://www.koonsolo.com/news/dewitters-gameloop/ und http://gafferongames.com/game-physics/fix-your-timestep/ .

Alternativ können Sie einen Timer erstellen und diesen Timer so einstellen, dass Ihr Update ausgeführt und alle X Millisekunden gerendert wird. Es gibt jedoch einige Nachteile beim Aufbau eines solchen Gameloop.

Laut http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Timer.html : " Jedem Timer-Objekt entspricht ein einzelner Hintergrund-Thread, mit dem alle Timer ausgeführt werden Aufgaben nacheinander. Timer-Aufgaben sollten schnell erledigt werden. Wenn die Ausführung einer Timer-Aufgabe zu lange dauert, wird der Task-Ausführungsthread des Timers "blockiert". Dies kann wiederum die Ausführung nachfolgender Aufgaben verzögern, die sich möglicherweise "zusammenballen" und schnell hintereinander ausführen, wenn (und wenn) die betreffende Aufgabe endgültig abgeschlossen ist. "

Laut http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Timer.html#scheduleAtFixedRate%28java.util.TimerTask,%20java.util.Date,%20long%29 : " Bei der Ausführung mit fester Rate wird jede Ausführung relativ zur geplanten Ausführungszeit der ersten Ausführung geplant. Wenn eine Ausführung aus irgendeinem Grund verzögert wird (z. B. durch Speicherbereinigung oder andere Hintergrundaktivitäten), werden zwei oder mehr Ausführungen schnell hintereinander ausgeführt „einzuholen“ . auf lange Sicht wird die Häufigkeit der Ausführung sein , genau der Kehrwert des festgelegten Zeitraums (vorausgesetzt , die Systemuhr Object.wait (long) korrekt Basiswert). "

Da Sie normalerweise nicht im Voraus wissen, wie lange eine Spielschleife dauert, kann das Einstellen eines Timers für die Ausführung Ihres Gameloops alle X Millisekunden (abhängig von der Zielbildrate) zu einigen gebündelten Bildern führen, die immer dann ausgeführt werden, wenn ein Bild ausgeführt wird beendet anstatt wann ein Frame geplant ist. Wenn das passiert ... warum überhaupt einen Timer verwenden?

Verstehen Sie mich nicht falsch, der Timer ist keine schlechte Klasse, aber er eignet sich normalerweise besser für kleine Aufgaben, die regelmäßig oder zu einem bestimmten Zeitpunkt ausgeführt werden müssen, z. B. wenn ein E-Mail-Client alle 5 nach neuen E-Mails suchen möchte Minuten, oder ein Zähler wird jede Sekunde dekrementiert, um einen Countdown vor dem Start eines Rennens anzuzeigen.

Exilyth
quelle
Die Frage betraf Spielschleifen, daher sind die awt / Swing-Informationen nicht zum Thema. Es sah jedoch so aus, als wären Informationen aufgrund einer irrelevanten und verwirrenden Zeile in der Frage relevant, also habe ich das entfernt.
Jhocking
Ich habe meine Antwort angepasst, um die an der Frage vorgenommenen Änderungen widerzuspiegeln.
Exilyth
7

Ich würde die Hauptschleife nicht in einen Timer stecken. Vielmehr würde ich eine 'while'-Schleife erstellen, die jeden Frame verarbeitet, und dann eine Art Zeitnehmungsfunktion verwenden (es klingt wie in Java, die System.nanoTime wäre), um zu berechnen, wie viel Zeit seit dem letzten Frame / der letzten Iteration des Frames vergangen ist Schleife.

Bestimmte Sprachen sind hier Ausnahmen (z. B. JavaScript, ActionScript), da diese Sprachen in einer Umgebung ausgeführt werden, in die eine implizite Hauptschleife eingebunden werden kann (z. B. der Browser, der Flash Player), diese Ausnahme jedoch nicht für Java gilt.

jhocking
quelle