我正在为新游戏编写关卡编辑器。问题是,我不确定用于存储数据的结构。
它是一个基于图块的地图引擎,使用x和y坐标以及该位置处的图块的id。
我有多个图层,地图可以调整大小,因此数组可能会给我带来一些麻烦,这就是我选择std :: vector的原因。 为了防止大量过载,我只添加一个瓷砖,当有人放置它时,如果没有瓷砖,矢量大小为零,并且增加了更多的瓷砖。
struct tile {
unsigned short tile_id;
unsigned short tile_x;
unsigned short tile_y;
};
我的矢量:
std::vector<tile> tiles;
问题是,在添加新图块之前,我需要检查是否已经在该x和y位置处的图块。
// Returns true/false if there is a tile at given position or not
bool Layer::has_tile_at(unsigned short x, unsigned short y) {
unsigned int i;
for (i = 0; i < tiles.size(); i++) {
if (tiles[i].tile_x == x && tiles[i].tile_y == y)
return true;
}
return false;
}
我的问题是,对于每个放置的瓷砖,我必须遍历整个矢量,这在开始时很快,但是在放置了一些瓷砖之后真的会感到痛苦。
你认为我的方法到目前为止还是没问题,还是有更聪明,更高效的方法?
答案 0 :(得分:3)
使用的数据结构应主要取决于用例:如果你主要做(x,y)读取,那么也许你需要一个矩阵(无论是通过矢量矢量,还是只是数组数组) )。
如果您需要索引访问并轻松迭代切片,可能会将数据保存在两个数据结构中。您应该能够轻松实现带有指向tile中tile的指针的二维地图 - 最初为空,懒惰地加载到(x,y)访问(记住数据安全性!)。
考虑例如:
class Map
{
public:
void addTile(std::shared_ptr<Tile> tile)
{
m_tiles.push_back(tile); // should probably remove old elements at (x,y) from the vector
m_map[{tile->x, tile->y}] = tile; // overwrites whatever was stored in there!
}
std::shared_ptr<Tile> getTile(int x, int y)
{
return m_tilesMap[{x, y}]; // if no tile there, returns default ctor-ed shared_ptr: nullptr
}
private:
std::vector<std::shared_ptr<Tile>> m_tiles;
using Index2D = std::pair<int, int>;
std::map<Index2D, std::shared_ptr<Tile>> m_tilesMap;
};
(带有简短代码示例的扩展注释:数据保存在堆上,而vector和map都保留了它的副本 - 也许可以进行改进以便于删除)
答案 1 :(得分:1)
为什么不使用多个向量?您可以通过使用向量向量来创建可增长的2-D向量,然后重载[]运算符以首先检查向量大小是否可以包含该元素(如果不包含则返回false),如果可以,则检查该元素是否可以不是构造的价值(无论你的默认值是什么&#34; tile&#34;可能是)。这将允许在常规向量中进行近似O(1)查找。否则,您可以使用公式来获得最大列/行距离,并使用某些2-D到1-D转换进行O(1)查找,例如在2-D数组中。
这就是我的想法:
vector< vector<tile> > tiles;
bool::Layer has_tile_at(unsigned short x, unsigned short y) {
if (tiles.size() <= x) {
return false;
} else if (tiles[x].size() > y) {
if (tiles[x][y] != tile()) {
return true;
}
}
return false;
}
编辑:
正如另一位用户指出的那样,你也可以使用指针并检查tiles [x] [y] == nullptr;代替!