如何在Javascript中正确声明和调用3维地图?
我正在编程一个minecraft类型的游戏。如何在Javascript中正确声明和调用3维地图?
基本上我有我的X,Y,Z和块类型。
如何声明这是最好的方式,所以当我输入XYZ坐标时,块的类型被返回?
E.G
function block(x, y, z, type) {
this.x = x;
this.y = y;
this.z = z;
this.type = type;
}
var map = new Array();
map[0] = new Array();
map[0][0] = new Array();
map[0][0][0] = new Block(0,0,0,grass);
map[0][0][1] = new Block(0,0,1,stone);
....
//hundreds of times later
ctx.drawImage(map[myPositionX][myPositionY][myPositionZ].type);
我似乎无法满脑子都在此就如何做到这一点没有它越来越混乱。
我可以只用对象吗?我必须拥有3D阵列吗?我不明白这一点
UPDATE
这真的是这样做的正确方法?
//Map
function Block(x, y, z, type) {
this.x = x;
this.y = y;
this.z = z;
this.type = type;
}
var map = [];
for(var i = 0; i < 100; i++){
map[i] = [];
for(var j = 0; j < 100; j++){
map[i][j] = [];
for(var k = 0; k < 10; k++){
map[i][j][k] = new Block(i,j,k,"neutral");
}
}
}
正在关注this answer。我创建了一个片段来展示如何将它集成到代码中。
现在,您可以map[142][156][123]
function setPropertySafe(obj) {
function isObject(o) {
if (o === null) return false;
var type = typeof o;
return type === 'object' || type === 'function';
}
if (!isObject(obj)) return;
var prop;
for (var i = 1; i < arguments.length - 1; i++) {
prop = arguments[i];
if (!isObject(obj[prop])) obj[prop] = {};
if (i < arguments.length - 2) obj = obj[prop];
}
obj[prop] = arguments[i];
}
function block(x, y, z, type) {
this.x = x;
this.y = y;
this.z = z;
this.type = type;
}
var map = {};
setPropertySafe(map, 142, 156, 123, new block(142, 156, 123, 'grass'));
console.log(map);
console.log(map[142][156][123].type);
谢谢!我认为这正是我需要的。虽然如果你可以澄清一下代码的工作原理,我会非常感激它 –
@ tery.blargh你可以按照问题的链接 – Weedoze
如今在Javascript数组是稀疏数组访问你的位置。 您可以定义两个帮助器方法来获取和设置一个块。 没有理由保持块坐标块本身,因此,一个块的唯一属性保持它的类型:
map = []; //array
getBlock = function(x,y,z) {
if (map[x] == null)
return null;
if (map[x][y] == null)
return null;
return map[x][y][z];
}
setBlock = function(x,y,z,type) {
if (map[x] == null)
map[x] = [];
if (map[x][y] == null)
map[x][y] = [];
map[x][y][z] = type;
}
这将让你开始。
最终你会意识到将一个块存储为Number
会占用太多内存。您必须将您的地图拆分为sectors
,其中每个扇区将编码多个块作为Number
。
在我看来,拥有一个三维位置数组并不是一个有效的方法,因为它随着O(xyz)的增长而增加。
是否有一个特定的原因,你会需要你的整个空间被覆盖?每个可能的xyz组合都有一个块吗?
更好的方法是将块存储在散列表(对象)或数组中。
function getCubeIdFromLocation({ x, y, z }, { min, cubeSize }) {
const cubeX = Math.floor((x - min[0])/cubeSize[0])
const cubeY = Math.floor((y - min[1])/cubeSize[1])
const cubeZ = Math.floor((z - min[2])/cubeSize[2])
return (`cube${cubeX}${cubeY}${cubeZ}`)
}
function getHashTableAndLookupCubes(...blocks) {
const hashBlocks = {}
const lookupCubes = {}
let min = [0, 0, 0]
let max = [0, 0, 0]
for (let i = 0; i < blocks.lenght; i++) {
const block = blocks[i]
hashBlocks[`block${i}`] = block
min = [
block.x < min[0] ? block.x : min[0],
block.y < min[1] ? block.y : min[1],
block.z < min[2] ? block.z : min[2],
]
max = [
block.x > max[0] ? block.x : max[0],
block.y > max[1] ? block.y : max[1],
block.z > max[2] ? block.z : max[2],
]
}
// lets say you divide the space in 10 for each dimension
const gridSize = [10, 10, 10]
const cubeSize = [
(max[0] - min[0])/gridSize[0],
(max[1] - min[1])/gridSize[1],
(max[2] - min[2])/gridSize[2],
]
const gridParameters = { min, max, gridSize, cubeSize }
for (let i = 0; i < hashBlocks.length; i++) {
const block = hashBlocks[i]
const cubeX = Math.floor((block.x - min[0])/cubeSize[0])
const cubeY = Math.floor((block.y - min[1])/cubeSize[1])
const cubeZ = Math.floor((block.z - min[2])/cubeSize[2])
const cubeId = `cube${cubeX}${cubeY}${cubeZ}`
// You could also use
// const cubeId = getCubeIdFromLocation({ x: block.x, y: block.y, z: block.z }, gridParameters)
if (lookupCubes.hasOwnProperty(cubeId)) {
lookupCubes[cubeId].children.push(block)
} else {
lookupCubes[cubeId] = { x: cubeX, y: cubeY, z: cubeZ, children: [] }
}
}
return ({ hashBlocks, lookupCubes, gridParameters })
}
getHashTableAndLookupCubes(blockList)
如果你有很多块,以限制需要搜索的,你可以缓存在有一个x,y,z位置,并且宽度高度深度“小方块”块的位置量,当在特定位置查找块时,仅查找相应立方体内的块。
你也可以在邻居变量和树搜索中缓存块的邻居。(在代码中未示出)
另一种可能性是使用a Proxy
在您使用的阵列提供的代码。这是做到这一点的一种方法。如果你觉得它舒适,去这个 – Weedoze
我不喜欢做数组的原因之一是我必须从0,0,0开始,并且不能跳进,比如说142,156,123;只有当我定义了一切。定义这样的事情需要很长的时间。没有其他更好的方法吗? –