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?
<some commercial engine>
sposób?Odpowiedzi:
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.
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.
źródło
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
staje się
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.
źródło
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).
źródło
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.
źródło