Richtiger Weg, um mit der Zerstörung von Spieleinheiten umzugehen


10

Stellen Sie sich eine Spielwelt vor, in der viele Entitäten ständig dynamisch geladen werden. Ich würde das vielleicht als Liste von Entitäten darstellen, aber was ist mit dem Entfernen?

Während ich beim Hinzufügen die neue Entität zurückschieben könnte, könnte ich die Notwendigkeit haben, irgendwo im Container zu entfernen. Welche Möglichkeiten habe ich, um zu vermeiden, dass das Element nach seiner Position zum Entfernen durchsucht wird?

Ich dachte, ich könnte die Entitäts-ID als ihre Position im Container speichern und einen Pfad für die direkte Entfernung erstellen, aber würde das nicht eine Art gegenseitige Abhängigkeitsstörung erzeugen?

Ich weiß, der richtige Weg wäre so etwas wie List.RemoveAt (whereToRemove); aber was ist, wenn nur das Wesen weiß, wann es sterben sollte?

Oder fehlt mir nur etwas und ein Listencontainer würde wissen, wann ein Objekt zerstört wird, und seine eigene Größe reduzieren?

Antworten:


10

Hier sind Ihre Bedingungen:

  • Andere Objekte können nach dem Entfernen noch von Ihrer entfernten Entität abhängig sein.

  • Sie möchten, dass nur die Entität ihre eigene Entfernung angibt.

Sie können nicht beide haben. Warum? Da Code auf einer höheren Ebene als Ihre Entität selbst (siehe Beispiele unten) entscheidet, wann diese Entität verwendet werden muss. Folglich kann nur Code auf derselben Ebene bestimmen, ob Ihre Entität zum Entfernen geeignet ist oder nicht.

Doch was kann passieren, dass das Unternehmen kann verlangen , seine eigene Entfernung von aus einem Ereignis feuern , die die höheren Level - Code für zuhört. Diese höhere Ebene speichert dann diese Anforderung zum Entfernen in einer Liste.


Beispiel 1: ohne Ereignisse

Sie überprüfen Kollisionen zwischen Entitäten in Ihrer Welt. Dies wird höher behandelt, normalerweise in Ihrer Hauptspielschleife, in der jede Entität gegeneinander geprüft wird. Wenn in diesem Beispiel eine Entität mit einer anderen kollidiert, kann nur die interne Logik dieser Entität bestimmen, wie viel Schaden sie erlitten hat und ob sie "abgelaufen" ist oder nicht. Folgen wir also dem Logikfluss für Kollisionen, bei denen Sie vier Entitäten in Ihrer Welt haben: A, B, C und D. A ist unsere Entität, um die es uns geht.

Wir prüfen A auf Kollision mit B. Es liegt eine Kollision vor. A erleidet 50% Schaden.

Wir prüfen A auf Kollision mit C. Es liegt eine Kollision vor. A erleidet 50% Schaden. Da der Schaden 0 erreicht, stellt A fest, dass er "gestorben" ist. Es entfernt sich von der Liste.

Wir prüfen A auf Kollision mit D. Es hätte keine Kollision gegeben, aber Sie werden nie so weit kommen: Sie erhalten eine Laufzeitausnahme, weil Ihre Entitätsliste während einer Traveraloperation geändert wurde.

Beispiel 2: mit Ereignissen

Gleiches Setup wie zuvor.

Wir prüfen A auf Kollision mit B. Es liegt eine Kollision vor. A erleidet 50% Schaden.

Wir prüfen A auf Kollision mit C. Es liegt eine Kollision vor. A erleidet 50% Schaden. Da der Schaden 0 erreicht, stellt A fest, dass er "gestorben" ist. Es wird ein Ereignis im Entitätsverwaltungscode ausgelöst, das besagt: "Entferne mich so schnell wie möglich". Der Entitätsverwaltungscode betrachtet die als Teil des Ereignisses gesendete Entitätsreferenz und speichert diese Referenz in einer Liste der zu entfernenden Entitäten.

Wir prüfen A auf Kollision mit D. Es gibt keine Kollision, und die Prüfung funktioniert einwandfrei.

Führen Sie nun am Ende der aktuellen Iteration der Spielschleife die Liste der zu entfernenden Entitäten durch und entfernen Sie jede dieser Entitäten aus Ihrer Liste der Hauptentitäten.


Sie können sehen, wie dies das Problem insgesamt vermeidet. Sie müssen keine Ereignisse verwenden, Sie können Signale oder etwas anderes verwenden, aber das Prinzip ist dasselbe - entfernen Sie Entitäten erst, wenn Sie dies sicher tun können. Die Kehrseite dieses Ansatzes, um die Dinge sauber und ordentlich zu halten, besteht darin, dasselbe mit hinzuzufügenden Entitäten zu tun - stellen Sie sicher, dass Sie Verweise auf diese beibehalten und sie erst zu Beginn der nächsten Iteration der Spielschleife hinzufügen.

Vergessen Sie nicht, sowohl Ihre zu entfernenden als auch Ihre hinzuzufügenden Listen jedes Mal zu leeren, wenn Sie sie zum Hinzufügen / Entfernen Ihrer Hauptentitätsliste verwenden.

PS. Haben Sie keine Angst, Ihre Hauptliste zu durchsuchen, um einzelne Umzüge durchzuführen. Es ist ein wesentlicher Bestandteil des Entity-Managements, und selbst massive Listen lassen sich in der Regel sehr schnell durchlaufen - schließlich sind sie dafür entwickelt.


0

Sie suchen definitiv nach einer HashMap / HashTable . Eine Hashtabelle ist eine Karte, die einen Schlüssel einem bestimmten Wert zuordnet. Der Schlüssel kann ein beliebiger Schlüssel sein (z. B. die Entitäts-ID).


0

Ich denke, Sie könnten die Smartpointer- Idee verwenden, um die Freigabe für Sie vorzunehmen. In diesem Fall ist es nicht erforderlich, eine Liste aller Entitäten in Ihrem Code zu führen.

In einigen Fällen benötigen Sie eine Liste, um alle Objekte in Ihrem Spiel zu durchlaufen. Diese Liste kann einfach eine Linkliste sein, bei der das Einfügen und Entfernen von Objekten genau O (1) Zeit in Anspruch nimmt.

Um Ihre Geschwindigkeit noch weiter zu erhöhen, können Sie ein statisches Array (möglicherweise einen Vektor) verwenden. In diesem Fall müssen Sie zwei verknüpfte Listen innerhalb desselben Vektors verfolgen. Eine iteriert über gültige Objekte und eine über freie Objekte. Wenn der Smartpointer einen zu löschenden Ort markiert, entfernen Sie einfach diesen Zeiger und fügen ihn der Liste der freien Leerzeichen hinzu. Wenn Sie eine Entität hinzufügen, müssen Sie nur den ersten freien Raum entfernen, ihn mit dem Entitätszeiger füllen und dann zur Liste der gültigen Objekte hinzufügen.

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.