在内存中实现无限映射

Implementing endless map in memory

本文关键字:无限 映射 实现 内存      更新时间:2023-10-16

我将不得不在程序内存中实现一个无尽的3D光栅地图。映射可以从[0;0;0]开始,也可以不从[0;0;0]开始。地图的Y坐标限制为255,其他可能是无限的。(是的,现在,你可能已经猜到这是一个Minecraft地图)
我需要创建一些类,将有简单的McMap::getBlock(int x, short y, int z)McMap::setBlock(int x, short y, int z)方法。意味着我需要能够读取和写入数据。我还希望能够删除块,因此释放内存
为此应该使用什么?我认为最好的解决方案是使用如下结构的表:

int x|short y|int z|int block id|other values...
-----+-------+-----+------------+---------------
   55|     21|  666|           1|

但是我如何用c++实现这个,而不使用真正的MySql(那将是真正的过度杀戮)?此外,我不想在程序退出时保留映射,所以我希望数据在程序内存中。同样,考虑映射是无限的,因此坐标可以是,无论是什么。另外,不要忘记非常远的点可以被映射。此外,一个非常重要的事情要注意:我需要有一个有效的方法通过X, Y和Z坐标获取块-我想遍历所有块以找到其中一个。我已经包含了boost库

我认为你可能不需要在内存时间内拥有一个Minecraft世界的整个可能区域,因为这将是非常大的(1024000000 KM^2)。如果你只是试图保持任何人通常会在游戏期间访问内存的区域,我认为使用STL(标准模板库)访问它是完全可行的。

Minecraft世界总是以16X16X255块加载在游戏中。您可以将块存储在程序中的std::map中。这种方法有几个优点。首先,它允许基于Far Lands wiki条目的地图可玩区域之外的位置呈现。它还允许我的世界地图的稀疏表示,这将非常类似于实际的我的世界地图的渲染方式。只有您的程序使用的块被加载到std::map中,并希望保持合理的内存使用。你将能够代表任何区域,无论它在整个可能的Minecraft地图区域的可玩区域中的位置。

要实现这个,你只需要首先创建world数据类型:

using namespace std;
struct Block
{
     // Whatever information you care to store here...
};
typedef vector<block> Chunk;
typedef map<int, map<int, Chunk> > World;

然后访问单个块:

Block McMap::getBlock(int x, short y, int z)
{
    const int WIDTH = 16; // You might want to store these constants elsewhere
    const int HEIGHT = 255;
    int chunkx = x / WIDTH;
    int chunkz = z / WIDTH;
    return yourWorld[chunkx][chunkz][x + z * WIDTH + y * HEIGHT * WIDTH];
}

擦除数据块:

void McMap::eraseChunk(int x, int z)
{
    if (yourWorld.find(x)) // Tests to make sure that row exists in the map.
        yourWorld[x].erase(z);
}

使用这种方法的另一个好处是,通过为一个块创建一个聪明的构造函数,而不是像我一样使用typdedef,当你需要访问世界std::map中的新块时,你可以自动生成一个块,类似于在我的世界中只有当你访问它们时才能生成块。当你访问map中还不存在的对象时,它将调用该对象的默认构造函数。

你可以分解你的地图块,就像在minecraft。每个块都是 W * H * L (x y z)块。一个chunk就是一个3d数组。最好的做法是将其包装成一维数组:

BlockType* chunk = new BlockType[W * H * L];
BlockType block = chunk[x + z * W + y * W * H];

这是为了有一个良好的内存管理(并且比将整个可能的映射存储在数组中要好得多)。请注意,访问块中的块是O(1),这里应该非常快。

然后,您可以存储您的块。每个块被赋予2d坐标作为它的id。最快的(对于访问来说)应该是std::map:

std::map<ChunkCoord, ChunkType*> map;

访问块是快速的。你需要得到块(一个除法应该从点坐标中得到块坐标),然后你得到块。

数据块的访问时间为0 (log(numChunks))。

创建一个chunk就是分配内存并在map中创建一个新项。你仍然会受到电脑内存量的限制(游戏邦注:游戏世界中没有无限的空间),这就是为什么像《我的世界》这样的游戏通常会将未使用的数据块保存到磁盘上。保存到磁盘是拥有一个近乎无穷无尽的地图的唯一方法。

的难点在于找到WHL的合适值。为此,恐怕您必须进行大量的测试和测量……

注意:扩展这个想法会导致四叉树。您可以使用它们,但是它们可能占用太多内存。