Was ist ein gutes flaches Dateiformat zum Speichern einer 2D-Kachelkarte, die in jede Richtung unendlich wachsen kann?

9

Ich erstelle eine einfache Karten-Engine, die bei Bedarf automatisch in jede Richtung mit prozedural generierten Inhalten erweitert wird.

Was ist ein guter Weg, um Kartendaten zu speichern, die an einem 0,0-Ursprung verankert sind, damit eine rechteckige Teilmenge von Kartendaten von jedem Punkt auf der Karte schnell und effizient geladen werden kann?

Ich habe die Idee, dass ich die Karte möglicherweise in verschiedene Sektoren aufteilen und dann ein Header-Format verwenden sollte, um festzustellen, wo in der Datei ein bestimmter Sektor gespeichert ist. Ist das eine gute Technik oder gibt es bessere, effizientere Techniken, die ich mir ansehen kann?

Nathan Ridley
quelle

Antworten:

7

Ich würde davon abraten, eine einzige Flatfile für theoretisch unendliche Datenmengen zu verwenden.

Wenn Sie über eine theoretisch unendliche Datenmenge verfügen, benötigen Sie einen Direktzugriff , dh mehrere Dateien oder eine Datenbank, oder ein indiziertes Flatfile-Format, bei dem die bereits von Dateisystemen oder einer Datenbank gelösten Indexierungsprobleme erneut gelöst werden.

Wenn Sie Ihre Chunks auf mehrere Dateien verteilen, müssen Sie nur "% APPDATA% / game / map / -110 / 5000.dat" (oder einen anderen Dateinamen, wenn Sie möchten) erhalten, um den Chunk auf (-110, 5000) zu bringen beginnen sie zu komprimieren). Datenbanken benötigen nur eine Abfrage. Wenn ein Block keine Daten enthält, können Sie einfach nichts speichern. Eine einzelne flache Datei bietet nicht die Geschwindigkeit und den Komfort eines Direktzugriffs auf Anhieb.

In einer einzelnen Datei beliebiger Größe müssen Sie für einen schnellen Direktzugriff eine Garantie für die Position eines Datenblocks haben, was die Verwendung eines Index bedeutet (da eine rohe binäre Suche in Ihren Datenblöcken die Leistung beeinträchtigt und ein Raster in Ihrem erstellt Datei mit "leeren" Stellen gibt Ihnen das Problem von Byte56 ). Sobald Sie ein Indizierungssystem entwickelt, es effizienter gestaltet und sich eine API geschrieben haben, haben Sie so etwas wie das Dateisystem oder eine Datenbank neu erstellt. Wenn Sie dadurch nicht tatsächlich etwas gewinnen, ist es die Investition wahrscheinlich nicht wert. Zum Beispiel profitiert Steam massiv von ihren GCF / NCF-Dateiformaten.

Wenn Sie Sicherheit für Ihre Speicherungen wünschen, ist dies weiterhin möglich. Sie können beispielsweise jeden einzelnen Block verschlüsseln. Um zu verhindern, dass sie gelöscht werden, können Sie einen zentralen Hash basierend auf vorhandenen gespeicherten Daten verwenden. Wenn die gespeicherten Daten nicht mit dem Hash übereinstimmen (und Ihr Programm die Änderung nicht verursacht hat), wurde ein Block gelöscht.

Doppelgrün
quelle
4

Die am häufigsten verwendete Lösung scheint darin zu bestehen, sich in viele Dateien aufzuteilen. Ihre Frage impliziert jedoch nur eine einzige Datei. Die einzig sinnvolle Option hierfür (meiner Meinung nach) ist die Emulation eines sehr einfachen Dateisystems innerhalb dieser einzelnen Datei. Es ist eigentlich nicht schwer zu tun, aber Sie sollten wirklich in Betracht ziehen, mehrere Dateien zu verwenden, wenn Sie können.

Wenn Sie sich an eine Datei halten müssen, finden Sie möglicherweise Inspiration für Ihre Implementierung aus ext2 fs. http://en.wikipedia.org/wiki/Ext2 Ich weiß, dass es mir geholfen hat, einige gute Entscheidungen zu treffen, als ich einen einfachen FS für ein Spiel implementieren musste.

Aber wirklich, für jede wachsende Karte ist es normalerweise besser, nur eine Datei für jeden "aufgerufenen" Block zu verwenden.

Richard Fabian
quelle
4

Ich habe ein Chunking-System für mein Spiel implementiert, als ich mit unendlichen Welten herumgespielt habe (nicht sicher, ob ich sie behalten werde oder nicht). Für die Verwendung mit einer einzelnen Datei habe ich zunächst die Weltposition des Chunks verwendet, um einen Byte-Offset in die Datei zu berechnen. Dies setzt eine statische Blockgröße oder zumindest ein statisches Maximum voraus. Wenn der Benutzer jedoch für eine Weile in eine Richtung aufbrechen würde, würde diese Datei für ihre Größe ziemlich spärlich werden, da große Landflächen noch nicht generiert wurden und daher leere Stellen in der Datei vorhanden waren.

Ich habe auch ein Zwei-Dateisystem ausprobiert. Eine Datei enthält eine Zuordnung von "Chunk-Position" zu "Chunk-Datei-Offset" -Paaren. Der zweite enthält alle Brocken. Wenn ein neuer Block generiert wird, wird dieser einfach am Ende der Blockdatei abgelegt und sein Versatz wird in der Datei position-> offset gespeichert. Dies war ein Problem, als Sie viele Blöcke hatten und das Finden des Versatzes in der Datei position-> offset einige Zeit in Anspruch nahm. Wenn Sie dies für möglich halten, können Sie die Positions-> Versatzdaten beim Laden in eine Hash-Map laden, um einen schnellen Zugriff zu erhalten.

Ich verwende momentan die zweite Option, kann aber zu etwas anderem wechseln, wenn ich feststelle, dass die Leistung fehlt. Vielleicht können Sie mit diesen Informationen etwas erstellen, das für Sie funktioniert. Viel Glück!

MichaelHouse
quelle
Ich würde vorschlagen, in sqlite sqlite.org zu schauen . Es ist sehr eigenständig, indiziert, verarbeitet Blobs usw. Dies würde die Leistung verbessern und "Lücken" in Ihrer Datei beheben.
Daniel Blezek