Na przykład posiadanie podstawowej klasy GameObject z hierarchią głębokiego dziedziczenia może być przydatne do konserwacji ...
W rzeczywistości głębokie hierarchie są generalnie gorsze z punktu widzenia łatwości konserwacji niż płytkie, a nowoczesny styl architektoniczny obiektów do gier ma tendencję do płytkich podejść opartych na agregacji .
Myślę jednak, że takie podejście może powodować problemy z wydajnością. Z drugiej strony dane i funkcje wszystkich obiektów gry mogą mieć charakter globalny. To byłby problem z utrzymaniem głowy, ale może być bliżej optymalnie działającej pętli gry.
Pętla, którą pokazałeś, może powodować problemy z wydajnością, ale nie, jak wynika z późniejszej instrukcji, ponieważ masz dane instancji i funkcje składowe w GameObject
klasie. Problem polega raczej na tym, że jeśli traktujesz każdy obiekt w grze dokładnie tak samo, prawdopodobnie nie grupujesz tych obiektów inteligentnie - prawdopodobnie są one losowo rozrzucone po całej liście. Potencjalnie zatem każde wywołanie metody aktualizacji dla tego obiektu (niezależnie od tego, czy ta metoda jest funkcją globalną, czy też nie i czy obiekt ma dane instancji lub „dane globalne” unoszące się w tabeli, do której indeksujesz, czy cokolwiek innego), różni się od wywołania aktualizacji w ostatnich iteracjach pętli.
Może to wywierać większy nacisk na system, ponieważ może być konieczne stronicowanie pamięci odpowiednią funkcją do i z pamięci oraz częstsze napełnianie pamięci podręcznej instrukcji, co powoduje wolniejszą pętlę. To, czy można to zaobserwować gołym okiem (lub nawet w programie profilującym), zależy dokładnie od tego , co jest uważane za „przedmiot gry”, ile z nich istnieje średnio i co jeszcze dzieje się w twojej aplikacji.
Systemy obiektowe zorientowane na komponenty są obecnie popularnym trendem, wykorzystując filozofię, zgodnie z którą agregacja jest lepsza niż dziedziczenie . Takie systemy potencjalnie umożliwiają podzielenie logiki „aktualizacji” komponentów (gdzie „komponent” jest z grubsza zdefiniowany jako pewna jednostka funkcjonalności, na przykład rzecz reprezentująca fizycznie symulowaną część jakiegoś obiektu, która jest przetwarzana przez system fizyki ) na wiele wątków - w zależności od typu komponentu - jeśli to możliwe i pożądane, które mogą mieć wzrost wydajności. Przynajmniej możesz tak zorganizować komponenty, aby wszystkie komponenty danego typu aktualizowały się razem , optymalnie wykorzystując pamięć podręczną procesora. Przykład takiego systemu zorientowanego na komponenty omówiono w tym wątku .
Takie systemy są często silnie odsprzężone, co jest również dobrodziejstwem dla konserwacji.
Projektowanie zorientowane na dane jest podejściem pokrewnym - chodzi przede wszystkim o zorientowanie się wokół danych wymaganych od obiektów, aby dane mogły być efektywnie przetwarzane zbiorczo (na przykład). Zasadniczo oznacza to organizację, która próbuje utrzymać dane wykorzystywane w tym samym klastrze celowym razem i działać jednocześnie. Nie jest to zasadniczo niezgodne z projektem OO i można znaleźć trochę gadania na ten temat tutaj w GDSE w tym pytaniu .
W efekcie bardziej optymalne byłoby podejście do pętli zamiast oryginalnego
foreach(GameObject g in gameObjects) g.update();
coś bardziej jak
ProcessUserInput();
UpdatePhysicsForAllObjects();
UpdateScriptsForAllObjects();
UpdateRenderDataForAllObjects();
RenderEverything();
W takim świecie, każdy GameObject
może mieć wskaźnik lub odniesienie do własnej PhysicsData
lub Script
lub RenderData
, w przypadkach, w których mogą być potrzebne do interakcji z obiektami w sposób indywidualny, a rzeczywisty PhysicsData
, Scripts
, RenderData
, et cetera, że wszystko jest w posiadaniu odpowiednich podsystemów (symulator fizyki, środowisko hostowania skryptów, renderer) i przetwarzane zbiorczo, jak wskazano powyżej.
Jest bardzo ważne , aby pamiętać, że takie podejście nie jest cudownym środkiem, a nie zawsze przyniesie poprawę wydajności (chociaż jest ogólnie lepsza konstrukcja niż głębokiego drzewa dziedziczenia). Szczególnie prawdopodobne jest, że zasadniczo nie zauważysz różnicy w wydajności, jeśli masz bardzo mało obiektów lub bardzo wiele obiektów, dla których nie można skutecznie równolegle aktualizować.
Niestety nie ma takiej magicznej pętli, która byłaby najbardziej optymalna - każda gra jest inna i może wymagać dostrajania wydajności na różne sposoby. Dlatego bardzo ważne jest, aby mierzyć (profilować) rzeczy, zanim ślepo skorzystasz z porady jakiegoś przypadkowego faceta w Internecie.