I am making a game similar to Minecraft, and I am trying to fine a way to keep a map of Block objects sorted by their id. This is almost identical to the way that Minecraft does it, in that they declare a bunch of static final
Block objects and initialize them, and then the constructor of each block puts a reference of that block into whatever the Java equivalent of a std::map is, so there is a central place to get ids and the Blocks with those ids.
The problem is, that I am making my game in C++, and trying to do the exact same thing. In Block.h, I am declaring the Blocks like so:
//Block.h
public:
static const Block Vacuum;
static const Block Test;
And in Block.cpp I am initializing them like so:
//Block.cpp
const Block Block::Vacuum = Block("Vacuum", 0, 0);
const Block Block::Test = Block("Test", 1, 0);
The block constructor looks like this:
Block::Block(std::string name, uint16 id, uint8 tex)
{
//Check for repeat ids
if (IdInUse(id))
{
fprintf(stderr, "Block id %u is already in use!", (uint32)id);
throw std::runtime_error("You cannot reuse block ids!");
}
_id = id;
//Check for repeat names
if (NameInUse(name))
{
fprintf(stderr, "Block name %s is already in use!", name);
throw std::runtime_error("You cannot reuse block names!");
}
_name = name;
_tex = tex;
//fprintf(stdout, "Using texture %u\n", _tex);
_transparent = false;
_solidity = 1.0f;
idMap[id] = this;
nameMap[name] = this;
}
And finally, the maps that I'm using to store references of Blocks in relation to their names and ids are declared as such:
std::map<uint16, Block*> Block::idMap = std::map<uint16, Block*>(); //The map of block ids
std::map<std::string, Block*> Block::nameMap = std::map<std::string, Block*>(); //The map of block names
The problem comes when I try to get the Blocks in the maps using a method called const Block* GetBlock(uint16 id)
, where the last line is return idMap.at(id);
. This line returns a Block with completely random values like _visibility = 0xcccc
and such like that, found out through debugging.
So my question is, is there something wrong with the blocks being declared as const obejcts, and then stored at pointers and accessed later on? The reason I cant store them as Block&
is because that makes a copy of the Block when it is entered, so the block wouldn't have any of the attributes that could be set afterwards in the constructor of any child class, so I think I need to store them as a pointer.
Any help is greatly appreciated, as I don't fully understand pointers yet. Just ask if you need to see any other parts of the code.
std::map<uint16, const Block*>
. There is something wrong with usingstd::map
(a tree) to access a contiguous list of integer ids instead of usingstd::vector
, though. – Sean Middleditch Oct 31 '13 at 22:52std::unordered_map
instead which -- while being a pretty bad hash map -- is a lot better than a plainstd::map
unless you actually need ordered keys. A good design here for mods and such is to use a GUID to uniquely identify a block and then contiguous IDs for the actual blocks, with the mapping table saved out to serialized maps. – Sean Middleditch Nov 1 '13 at 2:25