Quote:Original post by archaos90
char spritefile[50]; public: Room(const char *file); void LoadRoom(const char *file);Room::Room(const char *file)void Room::LoadRoom(const char *file) FILE *roomfile; char sprfile[50]; roomfile = fopen(file, "r"); char tag[20]; char params[100]; while(fscanf(roomfile, "%s = %s", tag, params) != EOF) if (strcmp(tag, "WALL") == 0) sscanf(params, "%d - %d - %d - %s", &posx, &posy, &pass, sprfile); strcpy(rmap[posy][posx].spritefile, sprfile); else if (strcmp(tag, "COMMENT") == 0)
With code like this, I'm not surprised you have a segfault somewhere. I understand from things like the keyword 'class' that you are trying to write in this new-fangled language called "C++". Have you heard that we have this class that represents a string, called
std::string, and a whole new I/O system built on "streams" which are type-safe and work seamlessly with user-defined types? No? Well, the language was
only most recently standardized about ten years ago, so...
Not to mention, there is normally no point in factoring out a constructor's work to a separate function like that (don't "reset" a room, just construct another one), no point in an empty else-if block, and it's trivial to convert an integer to a boolean without conditional logic. It's also strange to include "Room" in the name of "Room"'s member functions - do you put wallet money in your wallet? Oh, and a "class" that has everything public is simply a "struct"; C++ does not distinguish those except for private/public considerations.
Oh, and you probably don't want to
load the image from the hard drive,
every time you draw
each tile of the room. Instead, make an associative mapping of sprite file names to the loaded contents. This means you only open each file once. Fortunately, C++ makes this easy, with another helpful gadget called std::map.
#include <string>#include <fstream>#include <sstream>#include <map>struct Sector { int posx; int posy; std::string spritefile; bool passable;};std::map<std::string, SDL_Surface*> sprite_mapping;struct Room { Room(const std::string& filename); void Draw(SDL_Surface *to); int rootx; int rooty; Sector rmap[100][100]; };Room::Room(const std::string& filename) { ifstream file(filename.c_str()); // the "open" is implicit. std::string line; while (std::getline(file, line)) { // There's this other thing that also exists in C called // "scoping your variables properly"... std::stringstream ss(line); // what we use to "re-parse" data. // Instead of having a whole suite of s* functions that mirror the f* // file I/O, we simply make a different kind of stream (from the string), // and then forget it's anything different at all. Polymorphism! std::string tag; char equals; ss >> tag >> equals; if (equals == '=' && tag == "WALL") { // Yes, you really can compare strings just like that! // We can avoid repeating ourselves, with a reference: Sector& s = rmap[posy][posx]; // Yes, we use it like a value, even though it's not a copy... // ... and we can read directly into its members instead of temporaries: ss >> s.posx >> s.posy >> s.pass >> s.spritefile; // Notice how we read into a bool, too. There's no magic format specifier // for that. // While we're at it, let's do that loading: std::string& name = s.spritefile; if (sprite_mapping.find(name) == sprite_mapping.end()) { SDL_Surface* sprite = SDL_LoadBMP(name); SDL_SetColorKey(sprite, SDL_SRCCOLORKEY, SDL_MapRGB(sprite->format, 0x00, 0x00, 0xFF)); sprite_mapping[name] = sprite; } // Otherwise, it was already loaded. } }}void Room::Draw(SDL_Surface *surface) { SDL_Rect pos; // C++ also lets you declare a counter variable directly in the for loop. // I think C99 does, too. for (int i2 = 0; i2 < 100; ++i2) { for (int i = 0; i < 100; ++i) { // spaces are your friends... const int TILESIZE = 50; // as are constants. Sector& s = rmap[i2]; pos.x = s.posx * TILESIZE; pos.y = s.posy * TILESIZE; pos.w = TILESIZE; pos.h = TILESIZE; std::map<std::string, SDL_Surface*>::iterator it = sprite_mapping.find(s.spritefile); if (it != sprite_mapping.end()) { SDL_Surface* sprite = it->second; SDL_BlitSurface(sprite, &sprite->clip_rect, surface, &pos); } } }}
Of course, it's quite possible that your
real problem is that you don't actually have 10,000 Sectors to read in from your file, and therefore you try to draw Sectors that aren't properly set up. The code illustrated will neatly sidestep that (although you will probably run into other issues), by simply trying to find an empty-string spritefile name (because the std::string will get
default-constructed, while a char[50] buffer will simply be left to contain whatever was already there in memory), observing that we don't have a corresponding SDL_Surface* loaded, and skipping that Sector.