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?
quelle
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.
quelle
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:
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.
quelle
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.
quelle
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.
quelle
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.
quelle
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.
quelle