Große Datenmängen (Map) speichern

  • VB.NET

Es gibt 28 Antworten in diesem Thema. Der letzte Beitrag () ist von Chris96.

    Benutze beim Speichern unbedingt einen Stringbuilder. Da wirst du einen ziemlichen Geschwindigkeitsvorteil feststellen.

    Du kannst das ganze schon mal um 1/8 kürzer machen, indem du das =5 in ein Zeichen zusammenfasst. Beispielsweise sowas: ";XidY" statt ";X Y=id". Für die ID benutzt du dann einen Buchstaben, damit du ihn von den Koordinaten unterscheiden kannst. Wenn du zum Beipiel festlegst, dass ID 5 = "." ist, dann sieht das so aus ";250.1"

    Allerdings wird es noch kürzer, wenn du von Strings ganz Abstand nimmst. Ich denke bei deiner Mapgröße kann man die Koordinaten auf Int16 umstellen und die ID auf Byte. Du speicherst einfach Int16Int16Byte hintereinander. 2 Int16 und 1 Byte belegen dabei 5 Byte. Dargestellt in Hexadezimal sieht dein ";250 1=5" dann so aus: "FA015".

    Skybird schrieb:

    Das sind ja Ubisoftmethoden hier !

    @vb-checker
    Das habe ich doch schon gesagt? Außerdem sehe ich keinen Sinn darin, die Koordinaten mitzuspeichern, da sowieso jedes Feld in einem gewissen Bereich gespeichert wird.
    Hier mal ein kleines Beispiel, wie ich es machen würde (zwar in C#, sollte sich aber ohne Probleme manuell oder auch über Konverter konvertieren lassen:

    C-Quellcode

    1. public void SaveMap(Tile[,] map, string path)
    2. {
    3. FileInfo fi = new FileInfo(path);
    4. using (FileStream fs = fi.OpenWrite())
    5. using (BinaryWriter bw = new BinaryWriter(fs))
    6. {
    7. bw.Write(map.GetLength(0));
    8. bw.Write(map.GetLength(1));
    9. for (int x = 0; x < map.GetLength(0); x++)
    10. for (int y = 0; y < map.GetLength(1); y++)
    11. bw.Write((byte)map[x, y]);
    12. }
    13. }
    14. public Tile[,] LoadMap(string path)
    15. {
    16. FileInfo fi = new FileInfo(path);
    17. using (FileStream fs = fi.OpenRead())
    18. using (BinaryReader br = new BinaryReader(fs))
    19. {
    20. int width = br.ReadInt32();
    21. int height = br.ReadInt32();
    22. Tile[,] map = new Tile[,] { };
    23. for (int x = 0; x < width; x++)
    24. for (int y = 0; y < height; y++)
    25. map[x, y] = (Tile)br.ReadByte();
    26. return map;
    27. }
    28. }
    29. public enum Tile : byte
    30. { Empty, Stone, Dirt, Diamond }


    MfG Stefan

    nafets3646 schrieb:

    Das habe ich doch schon gesagt?

    Ist richtig, ich habe den Text vor dir geschrieben, aber nach dir auf absenden gedrückt und wollte dann nicht alles wieder löschen ^^
    Außerdem sehe ich keinen Sinn darin, die Koordinaten mitzuspeichern, da sowieso jedes Feld in einem gewissen Bereich gespeichert wird.
    Das funktioniert nicht, wenn er nur die schon besuchten Bereiche speichert, es also Lücken gibt.

    Skybird schrieb:

    Das sind ja Ubisoftmethoden hier !

    Dann soll er da halt einfach einen weiteren Feldtyp für "noch nicht generiert" machen und trotzten alle Felder speichern. Nehmen wir doch mal dein Beispiel mit den zwei Int16 und dem einen Byte. Hier haben wir also 5 Bytes pro Feld -> sobald 1/5 der Map generiert ist, lohnt sich mein Vorgehen speichertechnisch.
    Gehen wir doch mal davon aus, dass er jetzt eine Map mit 1000x1000 Feldern hat. Meine Speichermethode benötigt hier konstant 1MB Speicher, wobei deine zwischen 5 Bytes und 5MB liegt. Die Methoden agieren halt unterschiedlich.

    Abschließend würde ich aber sagen, dass es, keinen großen Unterschied macht, da deine Methode im Extremfall ja "nur" 5 mal größer ist, was keine großen Probleme bereiten sollte, da wir uns sowieso nur im Megabyte-Bereich befinden.

    MfG Stefan

    nafets3646 schrieb:

    eine Map mit 1000x1000 Feldern

    Im Startpost sprach er sogar von 10.000 x 10.000.
    Allerdings hat er nur 20 verschiedene Zustände. Seien wir großzügig und geben ihm 32 mögliche Zustände. Das sind dann 5 Bits. Mit ein bisschen Bitshifting kann man also auf 5 bytes 8 Zustände speichern. Und wenn man wie von dir vorgeschlagen einen Zustand für "noch nicht generiert" benutzt und große noch nicht generierte Bereiche hat, wo also alle Bytes eh 0 sind, dann kann man mit einer simplen Lauflängencodierung nochmal sehr viel sparen. Da kommt man bestimmt unter 1 MB 8o (trotz größerer Map)

    Skybird schrieb:

    Das sind ja Ubisoftmethoden hier !

    @vb-checker
    Natürlich ist sowas möglich, jedoch glaube ich kaum, dass soetwas hier sinnvoll wäre, da es warscheinlich einfach zu kompliziert für den TE würde. Das Runterkompakten auf die Byte-Ebene wie in meinem oder deinem (ersten) Beispiel ist noch verhältnismäßig einfach, wenn es aber dann mit Bitshifting und auch deiner Lauflängencodierung losgeht, wird das warscheinlich einfach zu kompliziert für ihn.
    Erstmal danke das ihr euch so mit meinem Problem beschäftigt :)

    @nafets3646
    Deinen ersten Vorschlag zur Verbesserung meiner aktuellen Speichermethode verstehe ich ja noch aber dann hört´s auch schon wieder auf.
    Wie kann man denn den Laufweg durch das errechnen bestimmen ? - Der Spieler läuft ja kein Rechteck sondern eher wild durch die Gegend.

    Bei deinem Code Beispiel, so wie ich es jetzt verstanden habe, würde direkt die ganze Map gespeichert werden und nicht nur der gesehene Teil, oder hab ich da etwas falsch verstanden? - Das wären doch dann wieder unnötige gespeicherte Informationen oder sind die Unterschiede zum speichern nur bereits gesehener Teile nicht ausschlaggebend ?

    Mit den Binary-Writern hab ich mich bis jetzt noch nie auseinander gesetzt, scheint aber ja nicht so schwierig zu sein.

    @vb-checker
    Bei Begriffen wie BitShifting oder Lauflängencodierung hört mein Wissen, wie von euch schon geahnt, leider auf :/ .So intensiv hab ich mich noch nie mit speicher Methoden auseinander gesetzt...

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Chris96“ ()

    1. Lauflängencodierung ist was ganz anderes, schau mal hier: de.wikipedia.org/wiki/Laufl%C3%A4ngenkodierung.
    2. Bei meiner Methode wird das gespeichert, was du reingibst. Da kann natürlich auch nur ein Abschnitt gespeichert werden, aber bei Maps bis 1000x1000 Feldern ist es ja maximal 1 MB, Probleme sollten sich dadurch also nicht ergeben. Falls die Map größer sein sollte, kannste ja auch einfach nen Ausschnitt in die Methode reingeben, dieser wird dann auch abgespeichert.