Original Post
I am making a map editor for my game using Dev-C++ (i.e. g++ compiler) and OpenGL. I have a global static object: Map map; Which is the map object currently being edited. Since this is just a simple editor for my main project, i am not as concerned with the design, so i don't care if there is a better way of doing this. The object is obviously created at runtime (since it's not a pointer) and it is initialised with a new blank map. Then when i load a map, i create the data. But for some reason, i get some strange problems. 1) When i load the background image (as an OGL texture), it is drawn as a blank white square. I have debugged it (as far as i can with Dev-C++'s not so great debugger) and i have found that the image is passed to my draw function with a texture id of 2 and the function gets an id of 0. At first i found that it was because i had created a global static object as well as a pointer, i.e. i had created two objects. Once that was fixed it worked but now it doesn't again. 2) When i try to initialise my map with data from an XML file i get a runtime error which seems to come from when i create a tile object. Here is the source code: Note 1: The object map is declared at global scope in Main.cpp and declared as extern in the header file which Map.cpp includes. Note 2: i have marked the areas where the problems seem to occur. The full source code can be found here. I have tried everything to find the problem but unfortunately i have no idea what's going wrong. Any help would be appreciated. thanks [Edited by - XTAL256 on August 20, 2008 4:22:10 AM]
/////////////////////////////////////////////////////////////////////
// File: Map.cpp //
/////////////////////////////////////////////////////////////////////
#include "Main.h"
#include "Map.h"
Map::Map() {
isNew = true;
isSaved = true;
path = "";
fileName = "Untitled.bmf";
}
Map::Map(string p, string fName) {
isNew = false;
isSaved = true;
path = p;
fileName = fName;
}
Map::~Map() {
this->distroy();
}
void Map::create(XMLNode node) {
XMLNode child;
// Load background image
child = node.getChild("background");
background.image = new Image(child, "image");
XMLNode bgChild = child.getChild("parallax");
if (!bgChild.isEmpty()) {
background.parallaxX = stringTo<int>(bgChild.getAttribute("x"));
background.parallaxY = stringTo<int>(bgChild.getAttribute("y"));
}
else {
background.parallaxX = background.parallaxY = 0;
}
bgChild = child.getChild("scroll");
if (!bgChild.isEmpty()) {
background.scrollX = stringTo<int>(bgChild.getAttribute("x"));
background.scrollY = stringTo<int>(bgChild.getAttribute("y"));
}
else {
background.scrollX = background.scrollY = 0;
}
bgChild = child.getChild("wrapMode");
string type = bgChild.getAttribute("x");
if (type == "NONE") background.wrapX = NONE;
else if (type == "TILE") background.wrapX = TILE;
else if (type == "STRETCH") background.wrapX = STRETCH;
type = bgChild.getAttribute("y");
if (type == "NONE") background.wrapY = NONE;
else if (type == "TILE") background.wrapY = TILE;
else if (type == "STRETCH") background.wrapY = STRETCH;
// Load tiles from composite images
const int numImages = node.numChild("cimg");
for (int i = 0; i < numImages; i++) {
cimages.push_back(new CompositeImage(node.getChild("cimg",i)));
}
const int numTiles = node.numChild("tileList");
MapTile* temp;
for (int i = 0; i < numTiles; i++) {
child = node.getChild("tileList",i);
//### Runtime error here, it seems to be in MapTile construction
temp = new MapTile();
temp->set = cimages[stringTo<int>(child.getAttribute("imgId"))-1];
temp->imgTile = temp->set->tiles[stringTo<int>(child.getAttribute("tileId"))-1];
temp->x = stringTo<int>(child.getAttribute("x"));
temp->y = stringTo<int>(child.getAttribute("y"));
tiles.push_back(temp);
}
}
void Map::createNew() {
distroy(); // Delete old map
name = "Untitled"; description = "";
fileName = "Untitled"; path = "";
width = 800; height = 600;
viewX = 0; viewY = 0;
zoom = 1.0f; maxPlayers = 8;
background.image = NULL;
background.wrapX = NONE;
background.wrapY = NONE;
background.parallaxX = background.parallaxY = 0;
background.scrollX = background.scrollY = 0;
}
void Map::distroy() {
cimages.clear();
tiles.clear();
delete background.image;
delete preview;
}
void Map::draw(Graphics &g) {
if (background.image)
//### Here is where the image is drawn
g.drawImage(background.image, 0, 0, 400, 300);
for (int i = 0; i < tiles.size(); i++) {
// This should work but is just for testing at the moment
g.drawImage(tiles->set->image, tiles->x, tiles->y);
}
}
/* Loads data from an XML file */
void Map::load() {
XMLNode node = XMLNode::readFile((path+"/"+fileName).c_str());
viewX = 0; viewY = 0;
name = node.getChild("name").getText();
description = node.getChild("description").getText();
width = stringTo<int>(node.getChild("size").getAttribute("w"));
height = stringTo<int>(node.getChild("size").getAttribute("h"));
preview = new Image(node, "preview");
this->create(node);
}
/////////////////////////////////////////////////////////////////////
// File: Map.h //
/////////////////////////////////////////////////////////////////////
#ifndef _MAP_H_
#define _MAP_H_
#include "Graphics.h"
#include "Tile.h"
/* Terrain type and RGB colour */
enum TerrainType {
TER_NONE = 0, TER_COL_NONE = 0x00000000, // Black
TER_SOLID = 1, TER_COL_SOLID = 0x00FFFFFF, // White
TER_DIRT = 2, TER_COL_DIRT = 0x00FF0000, // Red
TER_ROCK = 3, TER_COL_ROCK = 0x000000FF, // Blue
TER_SAND = 4, TER_COL_SAND = 0x00FFFF00 // Yellow
};
class Map {
public:
bool isNew, isSaved;
string path, fileName; // Directory where map data is
string name, description; // Name of the map and a short description
Image* preview; // Preview image to show in GUI
int width, height; // Size of map (px)
int viewX, viewY; // Position of map in view
float zoom; // Zoom factor
int maxPlayers; // Maximum number of players
struct {
Image* image; // Background image
int parallaxX, parallaxY; // Parallax speed
int scrollX, scrollY; // Scroll speed
int wrapX, wrapY; // Tile or stretch background
} background;
vector<CompositeImage*> cimages; // Array of tile sets (Composite Images)
vector<MapTile*> tiles; // Array of tiles on the map
Map();
Map(string path, string file);
~Map();
inline void setPath(string p) { path = p; }
inline void setFileName(string n) { fileName = n; }
inline void setFullName(string full) {
path = full.substr(0, full.rfind('\\'));
fileName = full.substr(full.rfind('\\')+1);
}
inline void setFullName(string p, string n) {
path = p; fileName = n;
}
void load();
void save();
void create(XMLNode node);
void createNew();
void distroy();
void draw(Graphics &g);
};
#endif // _MAP_H_
/////////////////////////////////////////////////////////////////////
// File: Tile.cpp //
// Date: 17/8/08 //
// Desc: Defines a map tile object and composite image (tile set) //
// //
/////////////////////////////////////////////////////////////////////
#include "Main.h"
#include "Map.h"
#include "Tile.h"
CompositeImage::CompositeImage(XMLNode node) {
load(node);
}
CompositeImage::~CompositeImage() {
delete image; // Delete image data
delete terrain;
tiles.clear();
}
void CompositeImage::load(XMLNode node) {
numTiles = node.numChild("tile");
int ch; // Number of channels the original image had
// Load image and terrain data
image = new Image(node.getAttribute("img"));
terrain = new Image(node.getAttribute("terrain"));
XMLNode child;
ImageTile* temp;
for (int i = 0; i < numTiles; i++) {
child = node.getChild("tile", i);
temp = new ImageTile();
temp->x = stringTo<int>(child.getAttribute("x"));
temp->y = stringTo<int>(child.getAttribute("y"));
temp->width = stringTo<int>(child.getAttribute("w"));
temp->height = stringTo<int>(child.getAttribute("h"));
tiles.push_back(temp);
}
}
/////////////////////////////////////////////////////////////////////
// File: Tile.h //
// Date: 17/8/08 //
// Desc: Defines a map tile object and composite image (tile set) //
// //
/////////////////////////////////////////////////////////////////////
#ifndef _TILE_H_
#define _TILE_H_
class MapTile;
class CompositeImage;
class ImageTile {
public:
int x, y; // Position of tile on composite image
int width, height; // Size of tile
ImageTile() : x(0), y(0), width(0), height(0) {}
ImageTile(int x, int y, int w, int h) :
x(x), y(y), width(w), height(h) {}
~ImageTile() {}
};
class MapTile {
public:
int x, y; // Position of tile on map
CompositeImage* set; // Tile set this belongs to
ImageTile* imgTile;
MapTile() : set(NULL), imgTile(NULL), x(0), y(0) {}
MapTile(CompositeImage* cimg, ImageTile* imgTile, int x, int y) :
set(cimg), imgTile(imgTile), x(x), y(y) {}
~MapTile() {}
};
class CompositeImage {
public:
int width, height;
Image* image; // Image data
Image* terrain; // Terrain map
vector<ImageTile*> tiles; // List of tiles on this image
int numTiles;
CompositeImage(XMLNode node);
~CompositeImage();
void load(XMLNode node);
};
#endif // _TILE_H_