Programowanie gier Java 2D: Różne podejścia do tworzenia pętli gry


10

Jestem nowy w programowaniu gier Java, ale im więcej czytam, tym bardziej jestem zdezorientowany, ponieważ widziałem kilka różnych podejść do tworzenia pętli gier: 1. Standardowe podejście, które wykorzystuje klasę Timer (wydaje się być mniej precyzyjny). 2. Bardziej precyzyjne podejście wykorzystujące System.nanoTime. 3. Proste podejście, które wykorzystuje scheduleAtFixedRate.

Który z nich powinien być ogólnie preferowany i gdzie są zalety / wady każdego podejścia? Z góry dziękuję za wszelkie informacje.

Odpowiedzi:


7

W przypadku podstawowej pętli gry uruchomisz pętlę while, w której uzyskasz czas za pomocą nanoTime (), określisz ile czasu minęło od ostatniej klatki, a następnie zaktualizujesz swój gamestate i wyrenderujesz.

Korzystając z http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/System.html#nanoTime%28%29 , możesz odpytywać o upływ czasu. Gruntownie...

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

Ta podstawowa metoda może zostać ulepszona, np. Http://www.koonsolo.com/news/dewitters-gameloop/ i http://gafferongames.com/game-physics/fix-your-timestep/ .

Alternatywnie można utworzyć licznik czasu i ustawić ten licznik, aby uruchamiał aktualizację i renderował co X milisekund. Ale istnieją pewne wady związane z budowaniem takiej gameloopu.

Według http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Timer.html : „ Odpowiadający każdemu obiektowi Timer jest pojedynczy wątek w tle, który służy do wykonania wszystkich timerów zadania, sekwencyjnie. Zadania timera powinny się szybko kończyć. Jeśli zadanie timera zajmuje zbyt dużo czasu, „przerywa” wątek wykonywania zadania timera. To z kolei może opóźniać wykonywanie kolejnych zadań, co może „wiązać się” i wykonuj szybko po sobie, gdy (i jeśli) przestępcze zadanie w końcu się zakończy.

Zgodnie z http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Timer.html#scheduleAtFixedRate%28java.util.TimerTask,%20java.util.Date,%20long%29 : „ W przypadku wykonania ze stałą szybkością każde wykonanie jest planowane w stosunku do zaplanowanego czasu wykonania pierwszego wykonania. Jeśli wykonanie zostanie opóźnione z jakiegokolwiek powodu (takiego jak wyrzucanie elementów bezużytecznych lub inne działanie w tle), dwa lub więcej wykonań nastąpi w krótkim odstępie czasu „dogonić”. W dłuższej perspektywie częstotliwość wykonywania będzie dokładnie odwrotnością określonego okresu (przy założeniu, że zegar systemowy leżący u podstaw Object.wait (długi) jest dokładny).

Ponieważ zwykle nie wiesz z góry, jak długo trwa pętla gry, ustawienie timera do wykonywania gameloopa co X milisekund (w zależności od docelowej częstotliwości klatek) może prowadzić do kilku grupowanych klatek, które byłyby wykonywane za każdym razem, gdy ramka jest zakończone zamiast kiedy planowana jest ramka. Kiedy tak się dzieje ... po co używać timera?

Nie zrozumcie mnie źle, licznik czasu nie jest złą klasą, ale zwykle lepiej nadaje się do małych zadań, które muszą być wykonywane okresowo lub w określonym czasie, np. Klient poczty może chcieć sprawdzać, czy nie ma nowej poczty co 5 minut lub licznik może się zmniejszać co sekundę, aby wyświetlać odliczanie przed rozpoczęciem wyścigu.


Pytanie dotyczyło pętli gry, więc informacje o awt / swing są nie na temat. Wyglądało jednak na to, że ta informacja była istotna z powodu nieistotnej i mylącej linii w pytaniu, więc to usunąłem.
jhocking

Dostosowałem swoją odpowiedź, aby odzwierciedlić zmiany wprowadzone w pytaniu.
Exilyth

7

Nie umieszczałbym głównej pętli w zegarze. Zrobiłbym raczej pętlę „while”, która przetwarza każdą ramkę, a następnie użyłem pewnego rodzaju funkcji pomiaru czasu (brzmi to jak w Javie jako System.nanoTime), aby obliczyć, ile czasu minęło od ostatniej ramki / ostatniej iteracji pętla.

Niektóre języki są tutaj wyjątkami (np. JavaScript, ActionScript), ponieważ języki te działają w środowisku, które ma niejawną główną pętlę do podłączenia (np. Przeglądarka, Flash Player), ale ten wyjątek nie dotyczy Javy.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.