Ich arbeite an einem Projekt, bei dem die Spielwelt unregelmäßig geformt ist (denke an die Form eines Sees). Diese Form hat ein Raster mit Koordinaten darüber. Die Spielwelt ist nur auf der Innenseite der Form. (Noch einmal, denke Lake)
Wie kann ich die Spielwelt effizient darstellen? Ich weiß, dass viele Welten im Wesentlichen quadratisch sind und gut in einem 2- oder 3-dimensionalen Array funktionieren. Ich habe das Gefühl, wenn ich ein Array verwende, das quadratisch ist, verschwende ich im Grunde Raum und verlängere die Zeit, die ich brauche, um durch das Array zu iterieren. Ich bin mir jedoch nicht sicher, wie ein gezacktes Array auch hier funktionieren würde.
Beispielform der Spielwelt
%Vor%Bearbeiten: Die Spielwelt wird wahrscheinlich jeden gültigen Ort durchlaufen müssen. Also würde ich eine Methode machen, die es einfach macht.
Es gibt Rechenaufwand und Komplexität, die mit spärlichen Darstellungen verbunden sind. Wenn also der Begrenzungsbereich nicht viel größer ist als Ihre tatsächliche Welt, ist es wahrscheinlich am effizientesten, einfach den "verschwendeten" Platz zu akzeptieren. Sie handeln im Wesentlichen mit zusätzlicher Speicherauslastung, um schneller auf den Inhalt der Welt zugreifen zu können. Noch wichtiger ist, dass die "Waste-Space" -Implementierung einfacher zu verstehen und zu warten ist, was immer vorzuziehen ist, bis zu dem Punkt, an dem eine komplexere Implementierung erforderlich ist. Wenn Sie keine guten Beweise haben, dass es erforderlich ist, dann ist es viel besser, es einfach zu halten.
Sie können einen Quadtree verwenden, um den verschwendeten Speicherplatz in Ihrer Darstellung zu minimieren. Quad-Bäume sind gut für die Partitionierung von 2-dimensionalen Raum mit unterschiedlicher Granularität - in Ihrem Fall ist die feinste Granularität ein Spielfeld. Wenn Sie einen ganzen 20x20-Bereich ohne Spielquadrate hätten, könnten Sie in der Quad-Tree-Darstellung nur einen Knoten verwenden, um den gesamten Bereich darzustellen, statt 400 wie in der Array-Darstellung.
Benutze die Struktur, die du dir ausgedacht hast - du kannst sie später immer ändern. Wenn Sie ein Array verwenden möchten, verwenden Sie es. Hören Sie auf, sich Sorgen um die Datenstruktur zu machen, die Sie verwenden werden, und beginnen Sie mit dem Codieren.
Wenn Sie Code schreiben, bauen Sie Abstraktionen von diesem zugrunde liegenden Array ab, wie Sie es in ein semantisches Modell einfügen. Wenn Sie dann feststellen (durch Profiling), dass es Platzverschwendung ist oder langsam für die Operationen, die Sie benötigen, können Sie es austauschen, ohne Probleme zu verursachen. Versuchen Sie nicht zu optimieren, bis Sie wissen, was Sie brauchen.
Verwenden Sie eine Datenstruktur wie eine Liste oder eine Karte und fügen Sie nur die gültigen Koordinaten der Spielwelt ein. Das einzige, was du speicherst, sind gültige Orte, und du verschwendest keinen Speicher, der die Nicht-Spiel-Welt-Orte speichert, da du diese aus dem Mangel an Präsenz in deiner Datenstruktur ableiten kannst.
Am einfachsten ist es, einfach das Array zu verwenden und die Nicht-Spielespaß-Positionen mit einem speziellen Marker zu markieren. Ein gezacktes Array funktioniert vielleicht auch, aber ich benutze es nicht so oft.
Sie könnten die Welt als (ungerichtete) Graphik von Land- (oder Wasser) Flecken darstellen. Jeder Patch hat dann eine reguläre Form und die Welt ist die Kombination dieser Patches. Jeder Patch ist ein Knoten im Graphen und hat Graphenränder für alle seine Nachbarn.
Das ist wahrscheinlich auch die natürlichste Darstellung einer allgemeinen Welt (aber möglicherweise nicht die effizienteste). Vom Standpunkt der Effizienz wird es wahrscheinlich ein Array oder eine Liste für eine stark irreguläre Karte übertreffen, aber nicht für eine, die gut in ein Rechteck (oder eine andere regelmäßige Form) mit wenigen Abweichungen passt.
Ein Beispiel für eine stark irreguläre Karte:
%Vor%Es gibt praktisch keine Möglichkeit, diese in eine regelmäßige Form zu bringen (sowohl im Raumverhältnis als auch in der Zugangszeit). Das Folgende passt andererseits sehr gut in eine regelmäßige Form, indem es grundlegende geometrische Transformationen anwendet (es ist ein Parallelogramm mit kleinen fehlenden Bits):
%Vor%Ein anderer Weg wäre das Speichern einer Kantenliste - eines Linienvektors entlang jeder geraden Kante. Einfach auf Inklusion zu prüfen, und ein Quad Tree oder sogar ein einfacher Location Hash auf jeder Ecke kann das Nachschlagen von Informationen beschleunigen. Wir haben dies mit einer Höhenkomponente pro Kante gemacht, um die Wände eines Baseballstadions zu modellieren, und es hat wunderbar funktioniert.
Es gibt ein großes Problem, das hier niemand angesprochen hat: der große Unterschied zwischen dem Speichern auf der Festplatte und dem Speichern im Speicher.
Angenommen, Sie sprechen von einem Spiel world , wie Sie gesagt haben, bedeutet dies, dass es sehr groß wird. Du wirst das ganze Ding nicht einmal im Speicher ablegen, sondern du wirst stattdessen die unmittelbare Umgebung im Speicher speichern und aktualisieren, wenn der Spieler herumläuft.
Dieser Umgebungsbereich sollte so einfach, einfach und schnell wie möglich zugänglich sein. Es sollte auf jeden Fall ein Array sein (oder eine Reihe von Arrays, die beim Bewegen des Spielers ausgelagert werden). Es wird oft und von vielen Subsystemen Ihrer Spielengine referenziert: Grafik und Physik werden das Laden der Modelle, das Zeichnen, das Halten des Spielers auf dem Gelände, Kollisionen usw .; der Sound muss wissen, auf welchem Bodentyp der Spieler gerade steht, um den entsprechenden Tritt zu spielen; und so weiter. Anstatt diese Daten zwischen allen Subsystemen zu übertragen und zu duplizieren, können Sie sie, wenn Sie sie nur in globalen Arrays speichern, nach Belieben und mit 100% Geschwindigkeit und Effizienz aufrufen. Dies kann die Dinge wirklich vereinfachen (aber beachten Sie die Konsequenzen globaler Variablen!).
Aber auf der Festplatte möchten Sie es unbedingt komprimieren. Einige der gegebenen Antworten geben gute Vorschläge; Sie können eine Datenstruktur wie eine Hash-Tabelle oder eine Liste nur ausgefüllter Standorte serialisieren. Sie könnten sicherlich auch einen Octree speichern. In jedem Fall möchten Sie keine leeren Speicherorte auf der Festplatte speichern. entsprechend Ihrer Statistik würde das bedeuten, dass 66% des Raumes verschwendet werden. Sicher, es gibt eine Zeit, um über Optimierung zu vergessen und Just Work zu machen, aber Sie möchten nicht eine 66% -lepty Datei an Endbenutzer verteilen. Denken Sie auch daran, dass Disks keine perfekten Random-Access-Maschinen sind (mit Ausnahme von SSDs). mechanische Festplatten sollten noch mindestens einige Jahre laufen und am besten sequenziell funktionieren. Sehen Sie, ob Sie Ihre Datenstruktur so organisieren können, dass die Lesevorgänge sequenziell sind, da Sie mehr Terrain in der Umgebung streamen, während sich der Spieler bewegt, und Sie werden wahrscheinlich feststellen, dass es sich um einen spürbaren Unterschied handelt. Nimm mein Wort dafür nicht, ich habe diese Art von Ding nicht wirklich getestet, es macht einfach Sinn, richtig?
Tags und Links c#