Angesichts von DRY erscheint es wünschenswert, eine Sammlung verwandter Spielobjekte nur in einem Container zu speichern. Möglicherweise sind jedoch Untersammlungen dieser Objekte in verschiedenen Kontexten erforderlich. Es kann sinnvoll sein, diese spezifischen Untergruppen in bestimmten, besser geeigneten Behältern aufzubewahren. Dies erhöht den Aufwand, Objekte über Container hinweg zu verfolgen, beispielsweise wenn Objekte aus der Spielwelt entfernt werden.
Welche Möglichkeiten gibt es, um ein solches Design zu vereinfachen, und was sind die typischen Kompromisse?
Um zu zeigen:
In einem Multiplayer-Rollenspiel enthält der Server möglicherweise eine Sammlung von Spielcharakteren in einer Karte, die zum Nachschlagen nach ID geeignet ist.
world
map<id, Character> allCharacters
Ein Charakter kann sich auch in einem bestimmten Spiellevel befinden. Um alle Zeichen zu identifizieren, die in einer Ebene vorhanden sind, kann es angebracht erscheinen, für jede Ebene einen Container einzuführen, der die aktuell vorhandenen Zeichen enthält. Auf diese Weise können Sie eine gemeinsame Logik für alle Zeichen in dieser Ebene ausführen.
world
map<id, Character> allCharacters
[levels]
level1
vector<Character> charactersOnPlayfield
level2
vector<Character> charactersOnPlayfield
...
Wenn ein Charakter mit der Welt interagiert, sollten Nachrichten nur an Charaktere in Reichweite weitergeleitet werden. Dieses Interessenmanagement könnte erreicht werden, indem jede Ebene in ein Raster von Zellen unterteilt wird, in denen jeweils die aktuell darauf stehenden Zeichen gespeichert sind.
world
map<id, Character> allCharacters
[levels]
level1
vector<Character> charactersOnPlayfield
[cells]
cell1
vector<Character> charactersOnCell
cell2
vector<Character> charactersOnCell
...
level2
vector<Character> charactersOnPlayfield
[cells]
cell1
vector<Character> charactersOnCell
cell2
vector<Character> charactersOnCell
...
...
Die Charakterobjekte auf verschiedenen Abstraktionsebenen führen dazu, dass über Objektbesitz und Lebensdauer sorgfältig nachgedacht werden muss.
Beachten Sie, dass die in den Containern gespeicherten Zeichenobjekte natürlich Referenzen und keine Kopien sind. Außerdem gehe ich davon aus, dass keine Speicherbereinigung vorhanden ist.
quelle
Jedes Zeichen sollte auf die eine oder andere Weise alle Container kennen, in denen es enthalten ist. Dies kann explizit (eine tatsächliche Liste der Container, die darauf verweisen) und berechenbar sein (die Zeichenkoordinaten werden gespeichert, aus denen die tatsächlichen Zellvektoren abgeleitet werden können) ) oder unausgesprochen ("Zeichen können auch in einer dieser sechs Listen gespeichert sein, und ich werde mich nicht darum kümmern, welche zu verfolgen"). Oder eine beliebige Kombination der drei. Der wichtige Teil ist, dass es einfach und effizient ist, jeden Ort zu finden, der einen Charakter betrachtet.
Es sollte auch einen kanonischen Speicher geben, in dem alle Charaktere im Spiel gespeichert sind, z. B. Ihre allCharacters-Karte dort oben.
Ein Charakter lebt genau dann, wenn er in allCharacters enthalten ist. Wenn Sie es aus allCharacters entfernen möchten, entfernen Sie es aus jedem Container, der es ebenfalls enthält (was gemäß dem ersten Absatz einigermaßen effizient sein sollte), und Sie sind festgelegt.
Dies setzt voraus, dass Sie keine Speicherbereinigung haben. Wenn Sie dies tun, können Sie meistens davonkommen, dass der GC sich darum kümmert. Wenn Sie am Ende Lecks haben, erstellen Sie einfach einen Container mit schwachen Referenzen, der alle Entitäten enthält, und verwenden Sie diesen, um zu analysieren, welche Entitäten undicht sind.
quelle
Bei der Beantwortung meiner Frage aus den bisherigen Erfahrungen sehe ich grundsätzlich folgende Optionen:
Extrahieren Sie Ihre spezifischere Sammlung von Objekten jedes Mal aus der allgemeineren Sammlung, wenn Sie sie benötigen
Bewahren Sie Ihre spezifischere Sammlung in speziellen Behältern auf, wie im Beispiel für diese Frage angegeben
Verwenden Sie das Caching für bestimmte Perspektiven auf / Teilmengen der Spielobjekte
Zu den Faktoren für die Auswahl einer dieser Optionen gehören
Das Beobachtermuster kann dazu beitragen, die Notwendigkeit zu verbreiten, die anderen Teilmengen von Objekten zu ändern.
quelle