数据结构 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' beginend)。【参考方案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++的主要内容,如果未能解决你的问题,请参考以下文章

根据相互距离对 2D/3D 点数组进行排序的启发式方法

嵌入 Python 时共享数组的最简单方法

如何声明可以在整个程序中使用的全局 2d 3d 4d ...数组(堆版本)变量?

python能做啥游戏

映射分支瓦片路径

瓦片切图工具gdal2tiles.py改写为纯c++版本