Zum Beispiel könnte eine GameObject-Basisklasse mit einer tiefen Vererbungshierarchie gut für die Wartung sein ...
Tatsächlich sind tiefe Hierarchien für die Wartbarkeit im Allgemeinen schlechter als flache, und der moderne Architekturstil für Spielobjekte tendiert zu flachen, aggregationsbasierten Ansätzen .
Ich denke jedoch, dass dieser Ansatz zu Leistungsproblemen führen kann. Andererseits könnten die Daten und Funktionen aller Spielobjekte global sein. Das wäre ein Wartungsproblem, könnte sich aber einer optimal ausgeführten Spielrunde nähern.
Die von Ihnen gezeigte Schleife weist möglicherweise Leistungsprobleme auf, jedoch nicht, wie in Ihrer nachfolgenden Anweisung impliziert, da die GameObject
Klasse Instanzdaten und Memberfunktionen enthält. Vielmehr ist das Problem, dass Sie, wenn Sie alle behandeln Objekt im Spiel als genau gleich behandeln, diese Objekte wahrscheinlich nicht intelligent gruppieren - sie sind wahrscheinlich zufällig über diese Liste verteilt. Potenziell ist dann jeder Aufruf der Aktualisierungsmethode für dieses Objekt (ob diese Methode eine globale Funktion ist oder nicht, und ob als Objekt Instanzdaten oder "globale Daten" in einer Tabelle schweben, in die Sie indizieren, oder was auch immer) unterscheidet sich von dem Aktualisierungsaufruf in den letzten Schleifeniterationen.
Dies kann einen erhöhten Druck auf das System ausüben, da Sie möglicherweise den Speicher mit der entsprechenden Funktion in den Arbeitsspeicher verschieben und häufiger den Befehls-Cache neu füllen müssen, was zu einer langsameren Schleife führt. Ob dies mit dem bloßen Auge (oder sogar in einem Profiler) erkennbar ist, hängt genau davon ab, was als "Spielobjekt" angesehen wird, wie viele davon durchschnittlich vorhanden sind und was in Ihrer Anwendung sonst noch vor sich geht.
Komponentenorientierte Objektsysteme sind derzeit ein beliebter Trend und nutzen die Philosophie, dass die Aggregation der Vererbung vorzuziehen ist . In solchen Systemen können Sie möglicherweise die "Aktualisierungs" -Logik von Komponenten aufteilen (wobei "Komponente" grob als eine Funktionseinheit definiert ist, z. B. als das, was den physikalisch simulierten Teil eines Objekts darstellt, der vom physikalischen System verarbeitet wird ) auf mehrere Threads - nach Komponententyp unterschieden -, wenn möglich und gewünscht, die einen Leistungsgewinn haben könnten. Zumindest können Sie die Komponenten so organisieren, dass alle Komponenten eines bestimmten Typs Update zusammen , so dass eine optimale Nutzung der Cache der CPU. Ein Beispiel für ein solches komponentenorientiertes System wird in diesem Thread erläutert .
Solche Systeme sind oft stark entkoppelt, was sich auch positiv auf die Wartung auswirkt.
Datenorientiertes Design ist ein verwandter Ansatz - es geht darum, sich in erster Linie an den für Objekte erforderlichen Daten zu orientieren, damit diese Daten (zum Beispiel) effektiv in großen Mengen verarbeitet werden können. Dies bedeutet im Allgemeinen eine Organisation, die versucht, Daten, die für denselben Zweck verwendet werden, zusammen zu halten und gleichzeitig zu verarbeiten. Es ist nicht grundsätzlich mit dem OO-Design unvereinbar, und Sie können hier bei GDSE in dieser Frage einiges Geschwätz zu diesem Thema finden .
In der Tat wäre ein optimaler Ansatz für die Spielschleife anstelle Ihres Originals
foreach(GameObject g in gameObjects) g.update();
so etwas wie
ProcessUserInput();
UpdatePhysicsForAllObjects();
UpdateScriptsForAllObjects();
UpdateRenderDataForAllObjects();
RenderEverything();
In einer solchen Welt, jeder GameObject
könnte einen Zeiger oder Verweis auf seine eigene haben PhysicsData
oder Script
oder RenderData
für die Fälle , in denen Sie benötigen, mit Objekten auf individueller Basis zu interagieren, aber die eigentliche PhysicsData
, Scripts
, RenderData
und so weiter alle durch ihre jeweiligen Subsysteme im Besitz sein würde (Physik-Simulator, Script-Hosting-Umgebung, Renderer) und wie oben angegeben in großen Mengen verarbeitet.
Es ist sehr wichtig anzumerken, dass dieser Ansatz kein Wundermittel ist und nicht immer zu einer Leistungsverbesserung führt (obwohl er im Allgemeinen ein besseres Design als ein tiefer Vererbungsbaum ist). Es ist besonders wahrscheinlich, dass Sie im Grunde genommen keinen Leistungsunterschied bemerken, wenn Sie nur sehr wenige Objekte haben oder sehr viele Objekte, für die Sie die Aktualisierungen nicht effektiv parallelisieren können.
Leider gibt es keine solche magische Schleife, die am optimalsten ist - jedes Spiel ist anders und erfordert möglicherweise eine Leistungsoptimierung auf unterschiedliche Weise. Es ist also sehr wichtig, Dinge zu messen (zu profilieren), bevor Sie blindlings den Rat eines zufälligen Mannes im Internet befolgen.