根据我的经验,有几种不同的方法可以解决这样的问题,但我推荐的方法取决于您必须处理此问题的时间量以及您想要制作的范围(多大)这个游戏。
你目前的方法
目前我认为您使用大多数人认为最直接的方法,将体素存储在 3D 网格中
[Source].
但是您似乎遇到的两个问题是,没有一种明显的方法可以创建大于 1x1 的块,并且世界空间的 3D 网格在内存使用方面效率相当低(至于数组您必须为每个单元格分配内存,包括空白空间。JavaScript 也不例外)。
另一种方法
使用 3D 数组的替代方法是使用不同的数据结构,全名是稀疏体素八叉树。
简单地说,这是一个树形数据结构,它通过细分空间区域来工作,直到所有内容都存储完毕。
将正方形子划分为四个较小象限的 2D 形式称为四叉树,类似地,将 3D 等效项划分为八个象限,称为八叉树。这种方法通常更可取,因为它更有效,因为树仅在绝对必要时才占用更多内存,并且它们也可以打包到 1D 数组中(技术上也可以是 3D 数组)。
在一些基于块的游戏中,四叉树/八叉树使用的一种常见策略是采用适合树的一个较大象限的相同类型体素的区域,即简单地停止细分,因为没有理由去如果所有数据都相同,则更深。
他们可以进行的另一种优化称为稀疏,其中空白空间(空气)区域被简单地删除,因为空白空间没有做任何特殊的事情并且可以推断其位置。
[SVO Source]
[Z Order Curve Source]
推荐方法
除非你有几个月的时间来完成你的游戏并且你正在上大学,否则我真的不会推荐 SVO(尽管阅读可能会给你的任何老师留下深刻印象)。相反,我建议采用与 Minecraft 明显相同的方法。例如。一扇门是 1X2 的,但方块只能是 1x1,那就做两个方块吧。
在门的示例中,您总共将有四个独特的块,上半部分和下半部分各两个,每个打开或关闭两个变体。
例如
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;
}
}