Platformówki 2D: dlaczego uzależnić fizykę od liczby klatek na sekundę?

12

„Super Meat Boy” to trudna platformówka, która niedawno pojawiła się na PC, wymagająca wyjątkowej kontroli i skoków w pikselach. Kod fizyki w grze zależy od prędkości klatek, która jest zablokowana na 60 klatek na sekundę; oznacza to, że jeśli twój komputer nie będzie mógł uruchomić gry na pełnych obrotach, fizyka oszaleje, powodując (między innymi) spowolnienie postaci i upadek na ziemię. Ponadto, jeśli vsync jest wyłączony, gra działa bardzo szybko.

Czy osoby doświadczone w programowaniu gier 2D mogłyby wyjaśnić, dlaczego gra została tak zakodowana? Czy pętla fizyki działająca w stałym tempie nie byłaby lepszym rozwiązaniem? (Właściwie myślę, że w niektórych częściach gry używana jest pętla fizyki, ponieważ niektóre byty nadal poruszają się normalnie bez względu na liczbę klatek na sekundę. Z drugiej strony twoja postać biegnie dokładnie [fps / 60] tak szybko.)

W tej implementacji niepokoi mnie utrata abstrakcji między silnikiem gry a renderowaniem grafiki, która zależy od specyficznych dla systemu rzeczy, takich jak monitor, karta graficzna i procesor. Jeśli z jakiegoś powodu komputer nie jest w stanie obsłużyć vsync lub nie może uruchomić gry z dokładnością do 60 klatek na sekundę, zadziała spektakularnie. Dlaczego krok renderowania powinien w jakikolwiek sposób wpływać na obliczenia fizyki? (W dzisiejszych czasach większość gier albo spowalnia grę, albo pomija klatki). Z drugiej strony rozumiem, że oldschoolowe platformówki na NES i SNES zależały od stałej szybkości klatek w dużej mierze od ich kontroli i fizyki. Dlaczego tak jest i czy byłoby możliwe stworzenie w tym stylu wzornika bez uzależnienia od klatek na sekundę? Czy koniecznie jest utrata precyzji, jeśli oddzielisz renderowanie grafiki od reszty silnika?

Dziękuję i przepraszam, jeśli pytanie było mylące.

Archagon
źródło
Styczny do twojego pytania. Oto świetny artykuł, który dokładnie opisuje opisywane problemy oraz „właściwy” sposób radzenia sobie z opóźnieniami czasowymi i liczbą klatek na sekundę. gafferongames.com/game-physics/fix-your-timestep
num1
Naprawdę zaskoczyło mnie, że zrobiliby to w ten sposób. Przypuszczam, że tak musi być, ponieważ został zbudowany przede wszystkim na konsole, na których można polegać na liczbie klatek na sekundę. Niezadowalający!
Iain

Odpowiedzi:

7

Dlaczego?

Garść powodów, wybierz: nie wiedzieli nic lepszego. Jest szybszy i łatwiejszy do wdrożenia. Koncentrowali się bardziej na rozgrywce, a mniej na krawędziach, które w większości przypadków mogą się nie pojawić.

Wykonałeś całkiem niezłą robotę, tłumacząc dlaczego. Jestem pewien, że zauważyłeś, że jest wiele tematów na ten temat . Nie jestem pewien, czy znajdziesz satysfakcjonującą odpowiedź poza tymi, które wymieniłem.

Tetrad
źródło
„Nie wiedzieli nic lepszego” opisuje, dlaczego podjąłem takie podejście w przypadku „Jack jest głupcem”. Ale - polegałem na wywołaniu dt od ostatniej klatki z całą moją logiką. Ale - przy współrzędnych zmiennoprzecinkowych może to prowadzić do dziwnych, trudnych do odtworzenia błędów
lochok
4

SMB była pierwotnie grą konsolową, w której można bezpiecznie założyć, że może działać z prędkością 60 klatek na sekundę na wszystkich Xbox360 (no może 50 dla niektórych graczy PAL). Zakładając, że ustalony timepep upraszcza kod nieco.

Chociaż łatwo jest skalować wiele rzeczy według zmiennego timepeptu - „pos + = velocity * timestep”, dość trudno jest zrobić to poprawnie, gdy masz do czynienia z przyspieszeniami, wskaźnikami zmian przyspieszenia i tak dalej.

Oddzielenie rozgrywki i renderowania to dobre rozwiązanie w teorii , ale dobre wdrożenie (z dobrą interpolacją) jest dość trudne i rzeczy mogą się łatwo popsuć. Jest to dość rzadkie, aby tę technikę stosować w prawdziwych grach (chociaż robią to niektóre duże gry, szczególnie gry RTS, ale więcej do synchronizacji gier sieciowych).

Podczas projektowania stałej rozdzielczości ekranu, a także stałej liczby klatek na sekundę, możesz zrobić jeszcze jedną rzecz, aby przewijanie było wyjątkowo płynne. Możesz upewnić się, że gra przewija się o pełną liczbę pikseli na klatkę - unikając jakiegokolwiek „wahania subpikseli”, które można uzyskać, przewijając ułamkową liczbę pikseli na klatkę.

bluescrn
źródło
1

Oczywistym rozwiązaniem jest równoległe działanie 2 pętli - renderowanie co 1/60 sekundy i pętla gry co 1/60 sekundy.

Ale z moim doświadczeniem we Flashu (AS3, z którego jestem pewien, że powstał Super Meat Boy), harmonogram nie zawsze jest bardzo dokładny. Dokładność zależy również w dużym stopniu od środowiska. W samodzielnym odtwarzaczu Flash może mieć rozdzielczość poniżej milisekund. Ale gdy działa w niektórych przeglądarkach internetowych, jego dokładność staje się dokładnością liczby klatek na sekundę.

Zatem najbliższym sposobem na oddzielenie pętli renderowania i logiki gry jest oparcie wszystkich ruchów na czasie (i uruchomienie każdej klatki na podstawie czasu, jaki upłynął od ostatniej klatki). Może to wprowadzić bardziej skomplikowaną matematykę (np. Ciągłe stosowanie grawitacji zamiast zwiększania prędkości obiektu w ustalonych odstępach czasu). Ponieważ gra może opóźnić się o sekundę, a następnie gracz przesunie się o 200 pikseli w jednym kroku, wykrywanie kolizji i reakcja mogą stać się jeszcze bardziej skomplikowane. Jeśli programista wykrywa kolizję na podstawie ramki (sprawdzając kolizję za każdym razem), musiałby także przejść do wykrywania kolizji na podstawie czasu. A gdyby chcieli, aby było to naturalne, musieliby zastosować metodę grawitacji opisaną powyżej, która powoduje, że ruch obiektu jest krzywą (w przeciwieństwie do linii),

Ponkadoodle
źródło
2
Oryginalna gra Meat Boy była grą Flash. Super Meat Boy to gra w C ++.
Archagon
0

Nie wydaje mi się, żeby prosić o gry 2D na PC w 60 klatkach na sekundę. Nawet większość gier 2D jest teraz przyspieszana sprzętowo, więc osobiście nie martwiłbym się wymaganiem fps.

Prawdziwe pytanie brzmi: dlaczego nie używałbyś pikseli, gry są pełne kodów i skrótów.

Jeśli tworzysz grę opartą na fizyce (być może rzucanie ptakami?), Odpowiedź jest oczywista, ale klon super Mario? ruch oparty na czasie może być trochę większy.

PhilCK
źródło
Nie jest trudno odtwarzać je przy 60 klatkach na sekundę, ale nadal można łatwo znaleźć wyświetlacze o natywnych częstotliwościach odświeżania 50 Hz, 70–85 Hz i 120 Hz.
0

Aby uniknąć dziwnego zachowania w fizyce 2D, której używają?

Szczerze mogę po prostu zgadywać. Spróbuję wyjaśnienia:

Sercem gry jest główna pętla. Co w zasadzie wygląda tak:

while(gameRunning)
{
  updateGame(timestep);
  renderGame(timestep);
}

updateGame aktualizuje stan gry: sprawdza dane gracza, stosuje dane gracza w świecie gry i uruchamia symulację fizyki itp.

renderGame rysuje i animuje grę.

To łączy aktualizację fizyki z renderowaniem. Jeśli chcesz go rozdzielić, musisz użyć wątków i odpowiednio zsynchronizować każdy dostęp do danych renderowania i wątku gameUpdate do danych współdzielonych, np. Pozycji gracza. To może być skończone.

Innym problemem może być to, że symulacja fizyki wymaga stałego pomiaru czasu, aby działać stabilnie. Zależy to od tego, jak supermeatboy oblicza ruch (ponownie możemy zgadnąć, jak to zrobili;)).

Naiwnym podejściem byłoby (którego używam w mojej grze * westchnienie *):

position=position+speed*timestep;
speed=speed+acceleration*timestep;

Nazywa się to integracją Eulera i jest ogólnie uważane za zły pomysł. Jeśli czas nie jest stały, występują błędy obliczeniowe, które powodują, że symulacja jest mniej stabilna. Obiekt może poruszać się z nadmierną prędkością lub nie działać wcale lub przelatywać przez ściany poza ekranem. Nawet jeśli czas jest stały, integracja Eulera powoduje drobne błędy obliczeniowe. Lepiej użyj innej metody integracji, takiej jak RK4, lub użyj silnika fizyki.

Oprócz tego mogą wystąpić problemy z wykryciem kolizji, jeśli czas oczekiwania stanie się zbyt duży. Ponieważ kolizje między dwiema aktualizacjami gry nie są sprawdzane, obiekty mogą przechodzić przez przeszkody.

Stephen
źródło