在内存中实现无限映射
Implementing endless map in memory
我将不得不在程序内存中实现一个无尽的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中创建一个新项。你仍然会受到电脑内存量的限制(游戏邦注:游戏世界中没有无限的空间),这就是为什么像《我的世界》这样的游戏通常会将未使用的数据块保存到磁盘上。保存到磁盘是拥有一个近乎无穷无尽的地图的唯一方法。
的难点在于找到W、H和L的合适值。为此,恐怕您必须进行大量的测试和测量……
注意:扩展这个想法会导致四叉树。您可以使用它们,但是它们可能占用太多内存。
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- 将函数类成员映射到类本身内部
- 如何在 C# 中映射双 C 结构指针?
- 如何在C++中使用结构生成映射
- 使用std::函数映射对象方法
- 如何加载(或映射)文件部分的最大大小,但适合在Windows上的RAM
- C++映射分割错误(核心转储)
- 内联映射初始化的动态atexit析构函数崩溃
- 使用"std::unordereded_map"映射到"std::list"对象
- 如何从多映射中删除特定的重复项
- 在未初始化映射的情况下,将值插入到映射的映射中
- QT通过C++添加映射QML项目
- 在c++中访问int到类对象的映射时出错
- 在C++中搜索嵌套多映射值
- 错误处理.将系统错误代码映射到泛型
- C++匿名结构作为std::映射值
- 在映射中插入地址时,新运算符重载会导致无限递归
- 在C++映射上的迭代给出无限循环
- 在内存中实现无限映射