Map Datei lesen
-
Ich bin seit längere Zeit am Programmieren eines Mario klons(Super mario World SNES-version).
Ich habe das Spiel so fertig, dass man, jedoch ohne graphischen Elementen, spielen kann.
So, nun überarbeite ich meinem Datei-Auslese Algorithmus, der die Level-dateien lädt.
Bisher sehen die Dateien so aus:SizeX : 32 SizeY : 16 11111111111111111111111111111111 11111111111111111111111111111111 11111111111111111111111111111111 10000000111111111111111111111111 10000000010011111111111111111111 10000000000011111111111111111111 10000000000001111111111111111111 10000000000000000000000000000001 10000000000000000000000000000001 10000a00000000000000000000000001 10000000000000000000000000000001 10000000000000000000000000000001 10000000000000000000000000000001 10000000000000000000000000000001 10000000001000000010000010000001 11222222222111111111111111111111 0 = leerer weißer block 1 = blauer Block 2 = roter block a = Spieler Startpunkt
Der Code zum Auslesen (der ganze Code ist bisher schnell hingeschrieben, hoffentlich noch verständlich)
void LoadMap(char* cstring) { // Create the reading object. ifstream Settingsreader; bool failure=false; bool MapSizefound=false; bool MAPxfound=false; bool MAPyfound=false; bool Aufh =false; // Open the txt file and check for errors. Settingsreader.open(cstring); if (!Settingsreader.is_open()) { failure = true; } if (!failure) { // Create the char array which holds all informations from the text. // The string is going to be used to check for variables in the file. char TextInput[1024]; // contains the current word/phrase int YCounter = 0; char Checkobject[100] ; { // Erstelle einen char-zeiger. char *chrptr = Checkobject; // Leere nun den gesamten Inhalt des Arrays. for(int index=0; index<100; index++) { *chrptr = 0; chrptr++; } } unsigned int Count=0; while (Settingsreader >> TextInput) { for (int i=0;i < length(TextInput) ;i++) { if (TextInput[i]) { if (MapSizefound) // Übernehme erst die Daten wenn die Level Größe ermittelt wurde Map[YCounter][i] = TextInput[i]; else // Solange die Größe nicht bekannt ist verlege die Daten aus der Datei auf Checkobject und nach den Informationen gesucht werden kann { Checkobject[Count] = TextInput[i]; Count++; } } } // end for. if (MapSizefound) YCounter++; { for ( int index = 0; index < length(Checkobject); index++) { if (Checkobject[index] == 'S' && Checkobject[index+1] == 'i' && Checkobject[index+2] == 'z' && Checkobject[index+3] == 'e' && Checkobject[index+4] == 'X' && Checkobject[index+5] == ':' && !MAPxfound && !Aufh) { int VAR_X = 0; index = index + 6; while (Checkobject[index] >= '0' && Checkobject[index] <= '9') { VAR_X *= 10; VAR_X += Checkobject[index] - '0'; index++; } if (VAR_X > 0) { MAP_X = VAR_X; MAPxfound = true; } } else if (Checkobject[index] == 'S' && Checkobject[index+1] == 'i' && Checkobject[index+2] == 'z' && Checkobject[index+3] == 'e' && Checkobject[index+4] == 'Y' && Checkobject[index+5] == ':' && !MAPyfound && !Aufh) { int VAR_Y = 0; index = index + 6; while (Checkobject[index] >= '0' && Checkobject[index] <= '9') { VAR_Y *= 10; VAR_Y += Checkobject[index] - '0'; index++; } if (VAR_Y > 0) { MAP_Y = VAR_Y; MAPyfound = true; } } } // end for } if (MAPxfound && MAPyfound && !Aufh) { MapSizefound=true; Free2DArray(Map); Map = Allocate2DArray< char >(MAP_Y, MAP_X); Aufh=true; } Sleep(10); } // while end // The data file can be closed Settingsreader.close(); // Now Search for spawnpoints bool PositionFound = false; for (int i = 0;i < MAP_Y;i++) { if (PositionFound) break; for (int j = 0;j<MAP_X;j++) { if (Map[i][j] == 'a') { INGAME.SetPosition(j*TileSize, i*TileSize); // Set The View to zero if (ViewPosX > 0) { View.Move(-(ViewPosX*TileSize),0); } if (j > 6 && j < MAP_X-6) View.Move( (ViewPosX = INFO_X = (j-6)*TileSize), 0); else if (j > MAP_X-5 && j < MAP_X-6) View.Move( (ViewPosX = INFO_X = (MAP_X-16)*TileSize), 0); else if (j >0 && j < 7) ViewPosX = INFO_X = 0; PositionFound=true; break; } } } // for end } // If (!Failure) end }
Map ist bisher ein globaler char Pointer auf ein 2d array der mit folgenden templates erstellt bzw gelöscht wird.
char** Map; template < typename T > T **Allocate2DArray( int nRows, int nCols) { //(step 1) allocate memory for array of elements of column T **ppi = new T*[nRows]; //(step 2) allocate memory for array of elements of each row T *curPtr = new T [nRows * nCols]; // Now point the pointers in the right place for( int i = 0; i < nRows; ++i) { *(ppi + i) = curPtr; curPtr += nCols; } return ppi; } template < typename T > void Free2DArray(T** Array) { delete [] *Array; delete [] Array; }
Nun aber möchte ich, dass Map ein struct wird, dass mehrere Informationen trägt :
struct TileWindows { bool solid; int collisionType; // Rechteck oder doch Steigung dabei ? Welcher typ ? Steigung mit welchem Winkel ? };
Zum Problem :
Eine Reihe von Zahlen einzulesen und zu speichern ist nicht sonderlich schwer.
Doch, wie stelle ich sicher, dass auf leicht lesbarer Weise solid und collisiontyp für jedes Element in eine Datei gespeichert werden, sodass diese leicht wieder zu laden sind?Gibt es Tutorials zu Data Input/Output Algorithmen ?
Ich danke im Voraus : D
-
xml?
-
Müsste ich für XML einen Parser selber schreiben, um mit den Schlüselwörtern klar zukommen oder gibt es dafür Funktionen ?
-
es gibt im Internet genügend XML Parser. Die sind auch so gebaut, dass du damit beliebige xml-Dokumente lesen kannst(ohne vorher die Struktur kennen zu müssen).
http://lars.ruoff.free.fr/xmlcpp/Ich hab bisher noch keine verwendet, deshalb kann ich keine empfehlungen aussprechen.
-
DerBaer schrieb:
xml?
yeah, da kommt der elefant und macht die mücke platt
-
no_code schrieb:
DerBaer schrieb:
xml?
yeah, da kommt der elefant und macht die mücke platt
dann mach doch nen besseren Vorschlag, dass es
* leicht lesbar
* leicht auszulesen istIch weiß das xml etwas umfangreich ist, aber halt shön übersichtlich und bei steigender Programmkomplexität auch immer effektiver...
-
evtl. mit der guten alten csv?
solid,collisiontyp\n solid,collisiontyp\n solid,collisiontyp\n solid,collisiontyp\n solid,collisiontyp\n
DerBaer schrieb:
und bei steigender Programmkomplexität auch immer effektiver...
das halte ich mal für ein gerücht. wie soll etwas immer effektiver werden? oder meinst du den workflow?
-
1,rechteck 1,steigung,links,45 2,steigung,links,30 3,rechteck 4,steigung,oben,17 3,steigung,unten,76
dann kommen vllt noch extras drauf:
1,rechteck,HausA(rot) 1,steigung,links,45,BaumA 2,steigung,links,30 3,rechteck,BaumC,Schlange(10HP, blau, o) 4,steigung,oben,17,HausB(grün) 3,steigung,unten,76
Ich will nicht sagen xml ist toll aber ich hasse es wenn bei mir solche dateien entstehen...
PS. effektiver im vergleich zu cvs
-
DerBaer schrieb:
PS. effektiver im vergleich zu cvs
erklär mal wieso
-
naja wenn du cvs parst, hast du:
if (value[0] == "rechteck") { typ = 0; continue; } else if (value[0] == "schief") { typ = 1; steigung = value[1]; if (value[2] == ... } }
in xml machste einmal den parsealgo und der geht für beliebig komplexe strukturen und erzeugt nen simplen baum
und je unterschiedlicher die datensätze werden, desto mehr if else braucht man bei cvs. :p
-
DerBaer schrieb:
xml
halte ich nicht für angebracht
DerBaer schrieb:
cvs
csv
-
Hab nun in beiden Möglichkeiten reingeschaut, aber ich kann keine Code-Beispiele dazu finden.
Ich habe mich nun dazu entschieden meine Level-daten in einer einfacheren Form zu speichern.
Das sieht nun folgendermaßen aus :SizeX : 3 SizeY : 2 1 1 12, 1 0 14, 1 1 16 1 2 12, 0 0 1, 0 0 1
Die erste Zahl sagt aus, ob die Fläche begehbar ist.
Die zweite Zahl sagt aus, welche collisionmethode für diese Fläche benötigt wird.
Die dritte Zahl sagt aus, welches Bild in die Fläche gezeichnet werden soll.
-
Mach doch sowas binär?
struct Surface { uint8_t isWalkable; uint8_t collisionType; uint16_t imageId; }; struct MapHeader { uint16_t magic; uint16_t numSurfaces; uint16_t sizeX; uint16_t sizeY; }; //C++, kb das in C zusammenzufutzeln^^ using namespace std; template < typename data_t > data_t binaryRead(ifstream& fileHandle) { data_t buffer; fileHandle.read(static_cast<char*>(static_cast<void*>(&buffer)), sizeof(data_t)); return buffer; } MapHeader loadMap(ifstream& mapHandle, vector<Surface>& surfaces) { MapHeader header = binaryRead<MapHeader>(mapHandle); for(size_t i = 0; i < header.numSurfaces; ++i) surfaces.push_back(binaryRead<Surface>(mapHandle)); return header; }
Mal eben runtergetippt, sollte so gut funktionieren...