几个月前,我为一个学校项目制作了一个像Minecraft这样的小型地形发生器。 我这样做的方法是使用多个块。每个块包含一个存储块的三维数组。 此数组中的每个位置都与其包含的块的位置相对应。
blocks[x, y, z] = new Block();
现在我想添加不同大小的块。但是,我不能用我现在存储块的方式来做到这一点,因为更大的块必须分布在三维数组中的多个位置。 LEGO Worlds是一个具有不同大小的块(和不同形状)的游戏的例子。像这样的游戏如何存储所有这些小块?
我希望有人能帮助我。
我使用的语言是Javascript与WebGL结合使用。
提前致谢!
答案 0 :(得分:2)
根据我的经验,有一些不同的方法可以解决这样的问题,但我推荐的问题取决于你需要花费多少时间来处理这个问题以及你想要的范围(有多大)制作这个游戏。
您当前的方法
目前我认为您使用大多数人认为最直接的方法是将体素存储在3D网格中
但是你似乎遇到的两个问题是,没有一种明显的方法来创建大于1x1的块,并且世界空间的3D网格在内存使用方面效率相当低(至于一个数组,你必须为每个单元格分配内存,包括空白空间.JavaScript也不例外。
另类方法
使用3D数组的另一种方法是使用不同的数据结构,全名是稀疏的体素八叉树。
这简单来说就是一个树形数据结构,它通过细分空间区域直到所有内容都存储起来。
其中方形子分为四个较小象限的2D形式称为四叉树,同样3D等效分为八个象限,称为八叉树。这种方法通常是可取的,因为它的效率更高,因为树绝对必要时只占用更多的内存,它们也可以打包成一维阵列(技术上也可以是3D阵列)。
在一些基于块的游戏中使用quad / octree的常用策略是采用适合树的一个较大象限的相同类型体素的区域来简单地在那里停止子分区,因为那里有如果所有数据都相同,没有理由深入。
他们可以进行的其他优化被称为稀疏,其中空空间(空气)的区域被简单地删除,因为空的空间没有做任何特殊的事情并且可以推断出它的位置。
推荐方法
除非你有几个月的时间来完成你的游戏并且你在大学里,否则我不会推荐一个SVO(虽然阅读可能会给你的老师留下深刻印象)。相反,我建议采用与Minecraft相同的方法。例如。门是1X2但是块只能是1x1,然后只需要两个块。
在一个门的例子中,你将有四个独特的块,两个用于上半部分和下半部分,每个块的两个变化被打开或关闭。
E.G。
var cubeProgram; // shader program
var cubeVBO; // vertex buffer (I recommend combining vertex & UV coords)
var gl; // rendering context
// Preset list of block ID's
var BLOCK_TYPES = {
DOOR_LOWER_OPEN: 0,
DOOR_UPPER_OPEN: 1,
DOOR_LOWER_CLOSED: 2,
DOOR_UPPER_CLOSED: 3,
}
var BLOCK_MESHES = {
GENERIC_VBO: null,
DOOR_UPPER_VBO: null
DOOR_LOWER_VBO: null
}
// Declare a Door class using ES6 syntax
class Door {
// Assume X & Y are the lower half of the door
constructor(x,y,map) {
if (y - 1 > -1) {
console.error("Error: Top half of the door goes outside the map");
return;
}
this.x = x;
this.y = y;
map[x][y ] = BLOCK_TYPES.DOOR_LOWER_OPEN;
map[x][y-1] = BLOCK_TYPES.DOOR_UPPER_OPEN;
}
}