如何在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"); 
     } 
    } 
} 
+1

在您使用的阵列提供的代码。这是做到这一点的一种方法。如果你觉得它舒适,去这个 – Weedoze

+0

我不喜欢做数组的原因之一是我必须从0,0,0开始,并且不能跳进,比如说142,156,123;只有当我定义了一切。定义这样的事情需要很长的时间。没有其他更好的方法吗? –

正在关注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);

+0

谢谢!我认为这正是我需要的。虽然如果你可以澄清一下代码的工作原理,我会非常感激它 –

+0

@ 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