数据结构 2d/3d 瓦片数组 C++
Posted
技术标签:
【中文标题】数据结构 2d/3d 瓦片数组 C++【英文标题】:Data structure 2d/3d array of tiles C++ 【发布时间】:2017-01-22 20:28:11 【问题描述】:我正在为一款新游戏编写关卡编辑器。问题是,我不确定使用什么结构来存储我的数据。
它是一个基于瓦片的地图引擎,使用 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;
我的问题是,对于每个放置的瓦片,我必须循环遍历整个向量,这在开始时很快,但在放置一些瓦片后真的很痛苦。
到目前为止,您认为我的方法还可以吗,或者有什么更智能、更高效的方法吗?
【问题讨论】:
要使用的数据结构应该主要取决于用例:如果您主要进行 (x,y) 读取,那么也许您需要一个矩阵(通过向量的向量,或者只是数组数组)。如果您需要索引访问并轻松迭代图块,也许将数据保存在两个数据结构中?您应该能够轻松地实现带有指向向量内图块的指针的 2d 地图 - 最初是空的,在 (x,y) 访问时延迟加载(请记住数据安全!) 您能进一步解释您的最后陈述吗?谢谢! @elasticman 他这样做了。往下看答案。 【参考方案1】:要使用的数据结构应该主要取决于用例:如果您主要进行 (x,y) 读取,那么您可能需要一个矩阵(通过向量的向量,或者只是数组的数组)。
如果您需要索引访问并在图块上轻松迭代,则可以将数据保存在两个数据结构中。您应该能够轻松地实现带有指向矢量内图块的指针的 2d 地图 - 最初是空的,在 (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 都保存它的副本 - 也许可以改进以便更容易删除)
【讨论】:
感谢您的想法!你将如何迭代瓷砖?你会使用两个 for 循环吗? 我会使用 std::unordered_map 来完全避免迭代。 @elasticman 因为您在std::vector
中保留了一份数据副本,所以您可以轻松地对其进行迭代。如果您决定完全删除该向量,您仍然可以像向量一样遍历地图(good ol' begin
和 end
)。【参考方案2】:
为什么不使用多个向量?您基本上可以通过拥有一个向量向量来创建一个可增长的二维向量,然后重载 [] 运算符以首先检查向量大小是否可以包含该元素(如果不是则返回 false),如果可以,则检查该元素是否不是构造值(无论您的默认“平铺”可能是什么)。这将允许像在常规向量中一样进行几乎 O(1) 的查找。否则,您可以使用一个公式来计算最大列/行距离,并通过一些 2-D 到 1-D 转换(例如在 2-D 数组中)进行 O(1) 查找。
这就是我的想法:
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;而是!
【讨论】:
以上是关于数据结构 2d/3d 瓦片数组 C++的主要内容,如果未能解决你的问题,请参考以下文章