Also das Speichern der Daten ist eigentlich recht einfach. Der
BinaryWriter speichert die Rohdatensätze von bestimmten Typen (int, string, char, bool, ...).
Meine Klasse
Map besteht aus int und string Variablen. Ich gehe die einzelnen Variablen durch und übergebe deren aktuellen Wert einfach dem
BinaryWriter, der diesen Wert in der angegebenen Datei ablegt. Jeder weitere Wert wird einfach hinten an die Datei dran gehängt.
Im Prinzip würde die Datei so aussehen:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7:
| map.Name = "Test"; map.Width = 10; map.Height = 10;
Test\0000000000000000000000... |
In Wahrheit sieht die Datei etwas anders aus, weil sie alles Binär speichert. Aber zum Vorstellen ist das hier besser.
Beim auslesen funktioniert das ganze genau anders rum. Der
BinaryReader öffnet die Datei und ließt den string zuerst aus (der hört bei dem Zeichen "\0" auf; das ist das String-Abschlusszeichen). Da ein
int 4 Byte speichergröße hat, ließt der Reader bei
reader.ReadInt(); die nächsten 4 Bytes aus der Datei und wandelt diese in einen Integer um (also int). Diese Werte weiße ich dann wieder der
Map-Klasse zu.
Deshalb ist es von Vorteil, wenn du Logik und UI voneinander trennst.
Logik:
Was dein Problem mit den MultiArrays angeht, überleg mal:
Deine Karte im TD ist Zweidimensional, also hast du eine X- und eine Y-Achse. Wenn du also Logik von UI trennst, musst du zuerst mal dieses Feld im Speicher anlegen.
Sagen wir dein Feld ist 20x20 groß, dann erzeugst du ein Array in dieser größe mit einem passenden Typ. Da dir ja nur die Farben der Felder wichtig sind, bietet sich als Typ int oder Color an. Letzteres verursacht bei manchen Speichermethoden problemen, deshalb habe ich int genommen. Wenn du noch mehr Informationen über die Karte wissen solltest (z.B. Name), erstelle dir eine Klasse, die die ganzen Infos bereithält. Bei mir ist das die Klasse
Map. Hier wird die Feldgröße, der Name und das eigentliche Spielfeld angelegt.
Das eigentliche Spielfeld ist bei mir
map.MapData. Dieses Array wird in den Maßen [Breite, Höhe] angelegt, sodass es den X- und Y-Achsen entspricht.
Der Vorteil darin liegt nun dass du ganz einfach dein Spielfeld ändern kannst.
Wenn du z.B. das rechte, untere und diagonale Feld einer bestimmten Stelle markieren willst, kannst du einfach so vorgehen:
C#-Quelltext
1: 2: 3: 4: 5: 6:
| Map map = new Map("Karte schlagmichtot", 20, 20); int x = 8, y = 10; map.MapData[x, y] = Color.Red.ToArgb(); map.MapData[x + 1, y] = Color.Red.ToArgb(); map.MapData[x, y + 1] = Color.Red.ToArgb(); map.MapData[x + 1, y + 1] = Color.Red.ToArgb(); |
Du siehst also, die einzelnen Felder müssen nichts voneinander wissen um sie zu ermitteln oder zu manipulieren.
So das wäre der Logikteil.
Kommen wir zur UI:
Jetzt hast du ja alle Daten schon im Speicher liegen wie du sie brauchst. Nun musst du sie nur noch auf den Bildschirm bringen. In Version 2 von meinem Projekt steht drin wie es richtig geht.
Also zuerst einmal bracuhen wir die Größe der Zeichenfläche. Ich habe bei mir eine Klasse geschrieben die von
Control abgeleitet ist. Somit kann man sie einfach im Designer auf die Form ziehen und die Spielfeldgröße selbst bestimmen.
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27:
| class DrawingSurface : Control { Map map; SizeF tileSize; public DrawingSurface() { tileSize = new SizeF(Width / map.Width, Height / map.Height); }
protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e);
Graphics g = e.Graphics; for (int x = 0; x < Map.Width; x++) { for (int y = 0; y < Map.Height; y++) { g.FillRectangle(new SolidBrush(Color.FromArgb(Map.MapData[x, y])), tileSize.Width * x, tileSize.Height * y, tileSize.Width, tileSize.Height); g.DrawRectangle(new Pen(Color.Black, 2), tileSize.Width * x, tileSize.Height * y, tileSize.Width, tileSize.Height); } } } |
Hoffe ich konnte es klarer machen.
P.S.: Hier sind alle per Du
Nachtrag
Ich habe dir im Anhang noch zwei Bilder. Das eine zeigt dir, wie das Array prinzipiell im Speicher aussieht und das Andere stellt das Spielfeld dar. Du siehst, sie sind beide fast identisch. Sie haben nur eine andere Skalierung. Und genau diese Skalierung wird bei der Paint-Methode umgerechnet (bei
g.FillRectangle(...
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler