W jaki sposób silnik przypomina jednostki przetwarzania źródłowego?

9

W silniku Source (i jego poprzedniku, goldsrc, quake) obiekty gry są podzielone na dwa typy: świat i byty. Świat jest geometrią mapy, a istotami są gracze, cząstki, dźwięki, wyniki itp. (Dla silnika źródłowego).

Każdy byt ma funkcję myślową , która wykonuje całą logikę dla tego bytu.

Jeśli więc wszystko, co wymaga przetworzenia, pochodzi z klasy podstawowej z funkcją think, silnik gry może przechowywać wszystko na liście i, w każdej ramce, przechodzić przez nią i wywoływać tę funkcję.

Na pierwszy rzut oka ten pomysł jest rozsądny, ale może wymagać zbyt dużych zasobów, jeśli gra ma wiele podmiotów.

Jak więc silnik taki jak Source zajmuje się (przetwarzaniem, aktualizacją, rysowaniem itp.) Obiektami gry?

JulioC
źródło
2
Dlaczego to ważne, w jaki <some commercial engine>sposób?
Kaczka komunistyczna
8
@The Communist Duck, myślę, że prawdziwym pytaniem jest to, w jaki sposób działa silnik, aby móc się od nich uczyć?
podpunkt

Odpowiedzi:

5

Cóż, właściwie nie ma innego sposobu, aby to zrobić - będziesz musiał przejść przez pętlę i wzywać think()każdą jednostkę przynajmniej raz na kilka klatek.

Możesz umieścić byty we własnym wątku, ale wtedy masz cały koszmar synchronizacji stanu, co zdecydowanie nie jest tego warte.

Na pierwszy rzut oka ten pomysł jest rozsądny, ale może wymagać zbyt dużych zasobów, jeśli gra ma wiele podmiotów.

Właśnie dlatego silnik Source nakłada twardy limit na liczbę jednostek, które mogą istnieć jednocześnie : 4096 jednostek, z których tylko połowa (2048) może być połączona w sieć. Przekrocz jeden z tych limitów, a gra się zawiesi.

Dlatego też podczas tworzenia mapy zaleca się, aby nie używać więcej niż około 800 podmiotów.

BlueRaja - Danny Pflughoeft
źródło
Czy wywołania funkcji 2 ^ 12 wciąż nie są DUŻE dla każdej ramki?
JulioC,
@ Júlio: Cóż, przy 60 fps to 246k wywołań funkcji na sekundę - to dużo, ale zdecydowanie wykonalne na dzisiejszym sprzęcie. Pamiętaj jednak, że jest to absolutne maksimum dozwolone przed awarią silnika Source - zazwyczaj na mapie jest znacznie mniej jednostek.
BlueRaja - Danny Pflughoeft
5
Jednostki mają następny czas, funkcja myślenia nie jest nazywana każdą klatką i nie dla wszystkich jednostek. Pamiętam, że dla trzęsienia 2 minimalny czas myślenia wynosił 0,1 (100 ms), tylko 10 klatek na sekundę dla podmiotów przetwarzających.
bcsanches
„Możesz umieścić byty we własnym wątku, ale wtedy masz cały koszmar synchronizacji stanu, co zdecydowanie nie jest tego warte”. Sprawdź te slajdy Killzone 4, jeśli uważasz, że nie warto: de.slideshare.net/jrouwe/…
Tara
3

Kroki, o których wspominasz, najprawdopodobniej są wykonywane w oddzielnych silnikach. Po prostu proste silniki do gier mają je zwykle w jednym przebiegu. Twoja sekwencja

for each object
    do physics
    do game logic
    draw

staje się

call physics subsystem
call game logic subsystem
call drawing subsystem

Silnik fizyki zajmuje się pozycjami i rozmiarami.

Game Logic Engine zajmuje się interpretacją tego, co zmienił silnik fizyki (mógłby utrudnić pewne punkty orientacyjne ...), jakie cele mają postacie i jakie zachowanie powinni robić , uruchamia zaplanowane skrypty (ta funkcja myślenia ).

Silnik rysowania rysuje, które obiekty są widoczne, i wie, które obiekty są widoczne, ponieważ silniki Quake'a oszukują tutaj (patrz sekcja Rysowanie).

Radzę raczej przestudiować, w jaki sposób przeprowadzane są symulacje, a nie silniki gier. Istnieje ogromna popkultura związana z tworzeniem gier, a silniki gier są tworzone w imperatywnych językach (z powodu tradycji i szybkości); więc bardziej pouczające było dla mnie zdobycie dobrych podręczników (raczej teorii) i NASTĘPNIE spojrzenie na silniki (ćwiczenie), a nie patrzenie na silniki i układanki przez wiele godzin, jak to zrobili.

Fizyka

Całe pojęcie iteracji wszystkich bytów i robienia {think, draw} prawdopodobnie doprowadzi do problemów. Będą konflikty i tak dalej. Wierzę, że Valve ma Havoka i myślę, że Havok zajmuje się wystarczająco poprawną fizyką.

Myśleć

Funkcja Think jest uruchamiana, gdy czas w grze jest równy czasowi innemu . Działa w ten sposób w silniku Quake, a silnik Quake jest podstawą dla silników Half Life. NIE jest uruchamiany za każdym razem.

Wewnętrznie powinno to być proste iterowanie po liście podmiotów i sprawdzanie, czy upłynęło czasu na wywołanie funkcji think. Złożoność czasowa będzie wynosić O (N), gdzie N jest liczbą podmiotów.

Jeśli istnieje bardzo duża liczba podmiotów, powinieneś zmierzyć, jak bardzo poprawi to FPS. Zauważ, że z powodu prawa Amdahla jest to potencjalnie niewidzialne przyspieszenie. To znaczy, po prostu iterujesz przez wszystkie elementy, pomniejszasz i sprawdzasz jeden numer.

Przyspieszyłbym to, sortując byty według nextthink (utwórz listę wskaźników do bytów i sortuj je za każdym razem; nie tablicę bytów, ponieważ byty mogą zmienić swoje następne myślenie w dowolnym momencie, więc przestawienie ich w tablicy zajmuje O (N) zamiast O ( 1) na liście).

Powinieneś również spojrzeć na harmonogram O (1) w systemie Linux .

Remis

Silnik rysuje to, co jest w przybliżeniu widoczne z obszaru, w którym znajduje się kamera. Poziom gry to podział na drzewo, a obszar to liść tego drzewa. Nie będę zawracać ci głowy szczegółami na ten temat ... Więc jeśli jednostka jest widoczna, jest umieszczana w zestawie widocznych jednostek i są one rysowane.

Przechowują, które obszary są obszarami potencjalnie widocznymi. Nazywa się to „potencjalnie widocznym zestawem”, w skrócie PVS . Jest wizualizacja PVS , zielona kapsuła jest graczem, a wokół niego renderowana jest zawartość jego PVS.

użytkownik712092
źródło
2

Jeśli więc wszystko, co wymaga przetworzenia, pochodzi z klasy podstawowej z funkcją think, silnik gry może przechowywać wszystko na liście i, w każdej ramce, przechodzić przez nią i wywoływać tę funkcję.

Na pierwszy rzut oka ten pomysł jest rozsądny, ale może wymagać zbyt dużych zasobów, jeśli gra ma wiele podmiotów.

Właściwie umieszczenie wszystkiego na jednej dużej liście jest zwykle mniej niż pożądane; jeśli zgrupujesz byty na listach na podstawie, na przykład, ich typu, możesz lepiej rozdzielić przetwarzanie na wiele wątków. Na przykład, jeśli wiesz, że wszystkie jednostki typu Foo nigdy nie wchodzą w interakcje z innymi podmiotami podczas fazy symulacji, możesz je całkowicie odciążyć. Gdyby rozrzucono je willy nie chcąc na jakiejś dużej pojedynczej liście, byłoby to znacznie trudniejsze.

W tym momencie niekoniecznie musisz czerpać wszystko ze wspólnej klasy podstawowej; Źródło dość przesadza z nadużyciami spadkowymi w odniesieniu do tego, co w przeciwnym razie mogłoby zostać zaimplementowane jako dane w tym zakresie.

Oczywiście zawsze będziesz miał górną granicę liczby jednostek, które możesz przetworzyć na ramkę, nawet jeśli zaczniesz odciążać pracę do innych rdzeni. Nie można tego obejść, wystarczy mieć pojęcie o tym, jaki jest limit w swojej implementacji, i podjąć kroki w celu jego złagodzenia (odpowiednie wyrównywanie faz przetwarzania na obiektach, które ich nie będą potrzebować, unikając nadmiernej ziarnistości w obiektach itp. cetera).

BlueRaja - Danny Pflughoeft
źródło
1

To, co musisz wziąć pod uwagę i podążając za tokiem myślenia z poprzednich odpowiedzi, to to, że twoje działanie będzie miało również wpływ na to, kiedy i jak wywołasz te funkcje myślowe.

Patrząc na link, który opublikowałeś w silniku źródłowym, możesz również przeczytać, że możesz skonfigurować czasy myślenia i różne konteksty myślenia dla każdej ze swoich jednostek, oprócz oczywistego twardego limitu, który ktoś już wskazał, będzie to klucz do osiągnięcia wyższej wydajności z większą liczbą encji, albo poprzez tworzenie stopniowych aktualizacji, które zwiększają wydajność przetwarzania wymagającego dużej wydajności poprzez wiele ram wykonania, lub przez eliminowanie niepotrzebnego przetwarzania w zależności od bieżącego kontekstu (tj. encje, które są zbyt daleko lub poza postrzeganiem gracza, nie potrzebują ten sam poziom „myślenia szczegółowego”, jak postacie, które znajdują się blisko gracza, po prostu nie zobaczy postaci oddalonej o 2 mile od swojego nosa).

Istnieją także inne, bardziej szczegółowe poziomy optymalizacji, w zależności od konkretnej logiki gry i sytuacji.

Sergio Franco
źródło
„gracz po prostu nie zobaczy postaci 2 mil z daleka od nosa” Haha! Ale dlaczego nikt nie wskazuje, że korzystanie z funkcji wirtualnych jest bardzo wolne?
Tara,