UNPKG

collide-3d-tilemap

Version:
87 lines (72 loc) 2.76 kB
module.exports = function(field, tilesize, dimensions, offset) { dimensions = dimensions || [ Math.sqrt(field.length) >> 0 , Math.sqrt(field.length) >> 0 , Math.sqrt(field.length) >> 0 ] offset = offset || [ 0 , 0 , 0 ] field = typeof field === 'function' ? field : function(x, y, z) { return this[x + y * dimensions[1] + (z * dimensions[1] * dimensions[2])] }.bind(field) var coords coords = [0, 0, 0] return collide function collide(box, vec, oncollision) { // collide x, then y - if vector has a nonzero component if(vec[0] !== 0) collideaxis(0) if(vec[1] !== 0) collideaxis(1) if(vec[2] !== 0) collideaxis(2) function collideaxis(i_axis) { var j_axis = (i_axis + 1) % 3 , k_axis = (i_axis + 2) % 3 , posi = vec[i_axis] > 0 , leading = box[posi ? 'max' : 'base'][i_axis] , dir = posi ? 1 : -1 , i_start = Math.floor(leading / tilesize) , i_end = (Math.floor((leading + vec[i_axis]) / tilesize)) + dir , j_start = Math.floor(box.base[j_axis] / tilesize) , j_end = Math.ceil(box.max[j_axis] / tilesize) , k_start = Math.floor(box.base[k_axis] / tilesize) , k_end = Math.ceil(box.max[k_axis] / tilesize) , done = false , edge_vector , edge , tile // loop from the current tile coord to the dest tile coord // -> loop on the opposite axis to get the other candidates // -> if `oncollision` return `true` we've hit something and // should break out of the loops entirely. // NB: `oncollision` is where the client gets the chance // to modify the `vec` in-flight. // once we're done translate the box to the vec results var step = 0 for(var i = i_start; !done && i !== i_end; ++step, i += dir) { if(i < offset[i_axis] || i >= dimensions[i_axis]) continue for(var j = j_start; !done && j !== j_end; ++j) { if(j < offset[j_axis] || j >= dimensions[j_axis]) continue for(var k = k_start; k !== k_end; ++k) { if(k < offset[k_axis] || k >= dimensions[k_axis]) continue coords[i_axis] = i coords[j_axis] = j coords[k_axis] = k tile = field.apply(field, coords) if(tile === undefined) continue edge = dir > 0 ? i * tilesize : (i + 1) * tilesize edge_vector = edge - leading if(oncollision(i_axis, tile, coords, dir, edge_vector)) { done = true break } } } } coords[0] = coords[1] = coords[2] = 0 coords[i_axis] = vec[i_axis] box.translate(coords) } } }