Elegante Methode, um eine große Anzahl von Entitäten in einer Spielwelt zu simulieren


33

Angenommen, Sie haben ein Spiel, in dem es viele (viele, viele) Entitäten gibt, die einige Funktionen erfüllen, von denen nicht alle ständig benötigt werden oder in jedem Frame berücksichtigt werden müssen. Das konkrete Problem, an dem ich arbeite, ist eine detaillierte Simulation eines Körpers einschließlich seiner Organe.

Im Spiel hat jede Kreatur ihren eigenen Körper, der in kleinere Teile (Rumpf, Beine usw.) unterteilt ist. Manchmal enthalten diese Teile Organe, die eine bestimmte Funktion im Körper erfüllen. Ob ein Organ derzeit einem Zweck dient oder aktiv ist, ist eigentlich nie klar. Schließlich hat ein Tier möglicherweise einen leeren Magen, der daher nichts zu verdauen braucht. Es wäre ziemlich lächerlich, jedes Objekt in jedem Frame zu überprüfen oder zu simulieren, und es wäre sehr kostspielig, sobald Sie viele Kreaturen auf der Welt haben. Also überlegte ich, wie ich intelligent zwischen Objekten, die aktualisiert werden müssen, und solchen, die nicht aktualisiert werden müssen, unterscheiden kann.

Was ich mir ausgedacht habe, scheint zumindest eine gute Lösung zu sein. Es wird eine einfache Warteschlange / ein einfacher Stapel erstellt (wesentlich ist, dass jedes Element entfernt wird, sobald es gelesen wird; die Reihenfolge ist irrelevant), der so genannte "Aufmerksamkeitsstapel", in dem sich Objekte befinden, die simuliert werden müssen. Objekte, die Aufmerksamkeit benötigen, legen sich einfach auf den Stapel oder werden von anderen Objekten dort abgelegt. Diese Objekte würden wahrscheinlich eine einfache Schnittstelle mit einer simulate () - Funktion implementieren.

Angewandt auf mein bisheriges Aufschlussbeispiel würde dies bedeuten:

Der Spieler wählt aus dem Inventar etwas zu essen (angenommen, es ist Brot) und legt es in den Mund seines Charakters und der Mund wird auf den Aufmerksamkeitsstapel gelegt. Im nächsten Frame wird der Mund vom Stapel genommen und seine simulate () - Funktion aufgerufen. Da es ein Mund ist, wäre es vernünftig, hier das Kauen zu simulieren. Dies kann einige Frames dauern, in denen sich der Mund weiter auf den Stapel legt, bis entschieden wird, dass das Essen zum Schlucken bereit ist. In diesem Fall gibt der Mund das gekaute Brot in den Magen (ich weiß, es geht nicht direkt dorthin, aber die Speiseröhre wird zur Vereinfachung weggelassen), der dann ebenfalls auf den Aufmerksamkeitsstapel gelegt wird. Im nächsten Frame wird die Simulation des Aufschlussprozesses gestartet. Und so weiter für den Rest der notwendigen Organe.

Ein vorhersehbares Problem dabei sind im Leerlauf befindliche Objekte. Ein schlafendes Tier ist ein gutes Beispiel dafür. Dies könnte wie zuvor beschrieben geschehen, indem das schlafende Tier auf dem Stapel gehalten und jedes Mal überprüft wird, ob es aufgeweckt werden muss. Dies erscheint jedoch verschwenderisch, da dies das einzige ist, was getan wird. Um im Leerlauf befindliche Objekte effizienter zu gestalten, wollte ich eine Art Zeitplan hinzufügen, in dem zu einem bestimmten Zeitpunkt auszuführende Jobs gespeichert werden. Wenn ein Tier einschlafen würde, würde es einen Job auf diesen Zeitplan setzen, der für eine bestimmte Zeitspanne nach dem Einschlafen des Tieres geplant wäre. Dieser Job würde sich dann darum kümmern, das schlafende Tier wieder auf den Aufmerksamkeitsstapel zu legen. Nun könnte man sagen, dass ein schlafendes Tier, das nicht auf dem Aufmerksamkeitsstapel steht, nicht von etwas angegriffen werden kann, weil seine KI nicht simuliert wird.

Ich weiß ehrlich gesagt nicht, ob dies aufgrund mangelnder Erfahrung auch nur annähernd eine elegante Lösung für dieses Problem ist. Bin ich in der Nähe von etwas brauchbarem? Wie wird das normalerweise gemacht oder hat jemand Vorschläge oder bessere Lösungen?

Antworten:


10

Genau so haben wir dieses Problem in Stendhal gelöst . In unserem Fall passieren viele Dinge in regelmäßigen Abständen, aber nicht jede Runde: Heilzauber, Pflanzen wachsen etwas weiter, Leichen degenerieren, Gegenstände auf dem Boden verfallen.

Wir haben eine Zugnummer, die in jedem Zug erhöht wird. Außerdem führen wir eine Karte zukünftiger Abbiegezahlen, die auf eine Reihe von Objekten verweisen, die in dieser Runde benachrichtigt werden müssen.


Was ist, wenn in der Zwischenzeit etwas anderes mit dem Objekt interagiert? Zum Beispiel könnte das schlafende Tier von einem Schlagstein geweckt werden. Sollten Sie in diesem Fall den Zeitplan des Tieres entfernen?
Emiliano,

Das hängt von der Situation ab: Wenn die durchgeführte Aktion harmlos ist (wie das Aufwachen, während wir schon wach sind), lassen wir es einfach geschehen. Wenn die Aktion jedoch Ressourcen verbraucht, durchsuchen wir die ausstehende Warteschlange und entfernen sie.
Hendrik Brummermann

14

Klingt nach einem ähnlichen Problem wie bei Eingaben: Sie haben mehr als 100 Tasten auf der Tastatur, möchten aber nicht jede einzelne Taste in jedem Frame überprüfen. Was tun Sie also?

Zwei Antworten: Abfragen oder Systemnachrichten.

Polling = Fragen Sie zu jedem Zeitpunkt, zu dem es im Spiel tatsächlich wichtig wäre, den Status der Tastaturtasten (oder der Objekte in Ihrem Fall) ab. Den Rest der Zeit ignorieren Sie sie.

Nachrichten = Jede Tastaturtaste (Objekt) muss etwas in eine Nachrichtenwarteschlange stellen, wenn sie gedrückt oder losgelassen wird (wenn Aufmerksamkeit benötigt wird). Bei jeder Iteration der Spielschleife durchsucht sie die Warteschlange und löst alle Nachrichten auf, bevor sie fortfährt.


10

Also werde ich einen Schritt zurück von der Implementierung gehen und die Frage aus einer Designperspektive betrachten. Haben Sie einen soliden Plan für die Anzeige aller Details, die Sie in diese Simulation einbeziehen möchten?

Beispielsweise:

  • Kann der Spieler den Unterschied zwischen einem Tier mit leerem Magen und einem Tier mit vollem Magen erkennen?
  • Sind diese Informationen für sie in irgendeiner Weise von Bedeutung, wenn sie in Ihrem Spiel Interaktionsentscheidungen treffen?
  • Könnte ein Spieler, der das Tier beobachtet, das Ergebnis Ihrer simulierten Ereignisse beständig vorhersagen, oder würde eine Zufallszahl ausreichen?

Grundsätzlich gilt als Faustregel, dass Ihre Simulation nicht komplizierter sein darf als die Ausgabe. Am Ende des Tages, wenn die einzigen Animationen, die Sie für Schafe haben, Weiden sind, schlafen, weglaufen. Dann ist es wirklich egal, wie viele Faktoren in die Entscheidung über den zu wählenden Staat einfließen. Alles, was die Spieler sehen werden, sind Schafe, die nachts schlafen, vor Gefahr davonlaufen und tagsüber fressen.

Die Verhaltenssimulation macht eine Menge Spaß, aber Sie sollten immer die Erfahrung des Endbenutzers im Auge behalten.


Ja, der Spieler wird in der Lage sein, den Unterschied zu erkennen, und es gibt einige Auswirkungen auf das Gameplay, aber es ist im Moment eher eine Spielerei, um Spaß zu haben. So ähnlich wie das Wundsystem in der Zwergenfestung, das ebenfalls sehr detailliert, aber vernachlässigbar ist. Aber wie Sie bereits erwähnt haben, macht es viel Spaß, daran zu arbeiten, und das ist momentan mein Hauptaugenmerk.
Marc Müller

9

Ich hatte ein ähnliches Problem bei einem Spiel, an dem ich vor ein paar Jahren gearbeitet habe - die Simulation von Objekten war komplex und konnte nicht wirklich für jedes Objekt auf der Welt im Detail durchgeführt werden.

Die Lösung bestand darin, das LOD-Konzept für die Simulation zu verwenden. Objekte in der Ansicht des Players würden die vollständige Simulation ausführen. Objekte, die weit vom Player entfernt sind, führten in regelmäßigen Abständen eine stark vereinfachte Simulation durch. Wenn Objekte in die Ansicht des Spielers gelangen, wechseln sie vom regelmäßigen Update der Simulation zum detaillierten, regelmäßigen Update.


2

Lösung mit einem Zeitplan ist gut. Beachten Sie, dass jede Entität eine Liste von Zeigern auf ihre zukünftigen Aktionen haben sollte, die die Möglichkeit bietet, zukünftige Aktionen bei Bedarf ungültig zu machen. Dh Das schlafende Tier wacht sofort auf, wenn es angegriffen wird. Daher müssen Sie seine Aufweckaktion in Zukunft ungültig machen.


1

Hierfür gibt es ein Entwurfsmuster. Ich denke, es heißt Datenbankobjekte?

Grundsätzlich behält man ein "Template" -Schaf, das alle nicht-speziellen Schafe in der Spielwelt darstellen kann, zeichnet sie alle auf die gleiche Weise und behält die eindeutigen Daten innerhalb des Template-Objekts, beispielsweise als Tabelle der Schafstandorte und / oder -zeit -seit-Scher. Wann immer Sie ein Schaf einzigartig machen müssen, können Sie eine bestimmte Instanz erstellen, um dieses einzigartige Schaf zu verfolgen.

Gleiches gilt für Animationen. Wenn es sich um eine inaktive Animation oder ein Ereignis handelt, das allen Instanzen gemeinsam ist, kann sich dies in der Vorlageninstanz befinden, in der spezifischere Animationen separat geplant werden können.

Vor langer Zeit habe ich ein Spiel für einen Programmierwettbewerb geschrieben, dessen Hauptschleife "animate ()" für die gesamte Szene heißt. Es wurden Funktionszeiger verwendet, um inaktive Animationen nach Bedarf durch andere zu ersetzen, und es wurde die Technik verwendet, um geerbte Animationen zu unterstützen (z. B. Drehen eines Zeichens, das auf einer sich drehenden Disc steht).

Dies ähnelt der Verwendung eines Delegaten für die Animation.


3
Fliegengewichtmuster, meinst du?
topright

0

Würde eine Zustandsmaschine funktionieren? Das Tier befindet sich entweder in einem Schlafzustand, einem Fresszustand, einem Laufzustand usw. Für jeden Zustand ordnen Sie eine Liste aktiver Organe zu. So können Sie für jeden Frame, den Sie für jedes Tier besuchen, den Status aktivieren, eine Liste der Organe für diesen Status anzeigen und die Aktualisierung für jedes Organ ausführen.


Ich denke, das würde die Dinge komplizieren, weil es möglich sein muss, dass im Tier mehrere Dinge vorkommen. Nur weil der Magen etwas verdaut, heißt das nicht, dass das Herz aufhört zu schlagen oder das Tier aufhört zu laufen. Sicher, Sie könnten eine Menge von Zuständen definieren, von denen jeder bestimmte Funktionen berücksichtigt, aber die Menge der Zustände wäre wahnsinnig groß.
Marc Müller

Pro Status können mehrere Dinge passieren, da Sie alle aktiven Organe in einem Status speichern und jeden Frame einzeln ausführen. Vieles, was in Ihrer Simulation passiert, scheint jedoch mit Zustandsübergängen übereinzustimmen. ZB Kauen -> Verdauen. Aber ich denke, Sie haben Recht, dass ein Tier nicht nur einen Zustand haben kann. Es finden Zustandsübergänge statt, beispielsweise mit den Gliedmaßen, die nichts mit Zustandsübergängen im Verdauungssystem zu tun haben. Aber vielleicht ist es nur komplizierter als das, was Sie haben. Ich dachte nur, es könnte etwas zu bedenken sein.
Erik Engheim
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.