Hi, ich würde mich auch gerne in die Diskussion einklinken
Da sich ja schon ein paar Leute fleißig in den Programmablauf und die Bundles hacken, dachte ich mir ich sehe mir die Karten ein wenig genauer an. Mir gefallen die Möglichkeiten der rasterfreien Kartengestaltung, ich glaube CiM 2 könnte das erste Spiel sein in dem man ein Verkehrsnetz für eine (Klein)Stadt maßstabsgetreu nachbauen kann.
Mein Gedanke ist daher, ein Grundgerüst aus frei verfügbaren Kartendaten, z.B. OpenStreetMap, zu generieren, bestehend aus
* Heightmap
* bestimmten Bodentexturen, die den Verlauf von Straßen, Bahntrassen, Flüssen etc. nachbilden
* Bodentexturen wären auch für Gebiete denkbar (besiedelt, Ackerland, Wiese, Wald...)
* Wahrscheinlich nicht leicht machbar, aber denkbar wäre auch, Objekte zu generieren: Bäume, Gebäude, Straßen
Mit dem letzten Punkt rechne ich nicht wirklich, da das Objektformat nur schwer aus den Maps zu lesen ist und z.B. gewisse reale Straßenverläufe im CiM 2 nicht nachgebildet werden können. Außerdem ist die Verknüpfung der Straßen alles andere als trivial. Um eine reale Gegend 1:1 nachzubauen dürfte aber eine korrekte Heightmap und Markierungen für sämtliche Straßen völlig ausreichen.
Nun hab ich mich für ein paar Stunden in den Hex-Editor gehängt und das *.map-Format ein wenig analysiert...
Grundaufbau:
* Header: dynamisch, relativ kurz
* HeightMap: statisch, 16.793.604 Byte (2049 * 2049 * 4)
* TextureMap: statisch, 16.777.216 Byte (2048 * 2048 * 4)
* GameObjects: dynamisch
Header:
Der Header beginnt mit dem String "GameState+SerializableMetaData" und enthält ein paar Metadaten wie den Namen der Map, sowie ein PNG-Bild der Minimap (binär codiert). Am Ende des Headers findet sich nach einigen Nullen der String "GameState+SerializableTerrainData" und darauf die Reihenfolge der verwendeten Texturen.
Viel genauer hab ich da noch nicht reingeschaut, sind sicher noch ein paar wichtige Daten drin versteckt.
HeightMap:
Wie genau man den Einstiegpunkt findet, weiß ich leider nicht, nur so viel: Nach der "SerializableTerrainData" kommt eine Reihe von Nullen und wenn die erste Ecke nicht auf Höhe 0 ist, kann man den ersten Eintrag != 0 als Startpunkt wählen.
Die Heightmap ist eine statische, unkomprimierte Matrix (deshalb kann auch keine Map <32MB werden, je 16MB entfallen nämlich immer auf die Heightmap und Texturmap).
Jede Zeile besteht aus 2048 Feldern, aber die Heightmap wird über ihre Kanten definiert, daher stehen uns je Zeile 2049 Werte zur Verfügung. Mit 2049 * 2049 Werten zu je 32 bit kommen wir auf 16.793.604 Byte, was ca. 16MB entspricht.
Die Höhe wird in Werten von - 1.048,575 bis + 1.048,576 angegeben, im Spiel werden dann Höhenmeter daraus. Wir können also Berge mit bis zu 1km Höhe, bzw. Ozeane mit 1km Tiefe anlegen (aber praktisch keine Flüsse ;(). Die Zahlen werden einfach als 32bit signed Integer (little Endian) gespeichert. Um jedoch auf die spielinternen Höhenmeter zu kommen, wird an der drittletzten Stelle ein Komma eingefügt.
Zwei Beispiele:
06 b5 01 00
Als 32bit Integer interpretiert wird die Zahl 111877 daraus, mit den Komma vor der drittletzten Ziffer kommt man auf 111,877 m Höhe.
34 cf fc ff
Dieser Wert als signed Integer ergibt -209100 oder spielintern 209,1 m unter dem Meeresspiegel.
TextureMap:
Direkt auf die HeightMap folgt die TextureMap, diesmal nur mit 2048 x 2048 Einträgen, weil Flächen, nicht Kanten, definiert werden.
Zunächst etwas Grundwissen: Vielleicht ist dem ein oder anderen schon aufgefallen, dass es im Mapeditor nur 4 Texturen gibt. Das hat seinen Grund: Das aktuelle Kartenformat unterstützt nämlich nur die Verwendung von 4 Texturen. Eine Karte besteht immer aus einer Basistextur mit 100% Deckkraft. Auf diese können die anderen 3 Texturen mit beliebiger Deckkraft hinzugemischt werden. Daneben gibt es noch zwei Spezialtexturen: Den Betonboden aus den Städten und ein schwarzes Nichts (wozu auch immer das gut ist...)
Zurück zum Format; auch hier besteht jeder Eintrag aus einem 32-bit Wort mit folgender Belegung:
Byte 1, 2 und 3 geben jeweils die Deckkraft der 3 Nicht-Basistexturen an (Werte von 0 bis 255 werden übersetzt in 0% bis 100%)
Byte 4 bestimmt über die Basistextur mit einem recht eigenartigen Verhalten
- Werte unter 0x50 erzeugen das schwarze Nichts, je kleiner der Wert desto größer ist der schwarze Fleck auf dem Quadranten
- Werte über 0xa erzeugen den versiegelten Boden mit braunem Rand. Auch hier gilt: Je größer der Wert desto größer die ausgefüllte Fläche. Alle Werte dazwischen erzeugen die Basistextur mit 100% Deckkraft.
Nach exakt 16.777.216 Byte ist auch der Spaß vorbei und es geht weiter mit den
GameObjects:
damit hab ich mich noch gar nicht auseinandergesetzt, sry ;D
Also, was lässt sich damit anfangen?
- Heightmaps lassen sich aus frei verfügbaren Kartendaten generieren
- Bodentexturen können auch an beliebiger Stelle gezeichnet werden, die Auflösung (jedes Feld hat 4x4 Meter) ist auch hoch genug, um Straßen zu tracen.
- Die Spielfläche ist mit 8x8 km (also 64km^2) groß genug, um kleinere Städte maßstabsgetreu wiederzugeben.
=> einer Simulation von real existierenden Städten steht damit nichts mehr im Weg
Ich hab schon Ideen für einen Karten-Generator der mit OpenStreetMap-Daten arbeitet, aber bis da produktive Ergebnisse rauskommen wird wohl noch ein Weilchen vergehen.