Last active
December 26, 2021 23:52
-
-
Save JanHolger/31a5beae19d6271e0bbae16ef21d78df to your computer and use it in GitHub Desktop.
A javascript function that can do basic collision detection on n-dimensional boxes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
@param a The middlepoint coordinates and half extent sizes of the floating box (e.g. [x, y, z, w, h, d]) | |
@param b The middlepoint coordinates and half extent sizes of the static box (e.g. [x, y, z, w, h, d]) | |
@param v The "velocity" or "motion" vector that should be applied | |
@return The "velocity" or "motion" vector that can be applied without overlapping | |
*/ | |
function boxCollide(a, b, v) { | |
// Find the amount of dimensions from the element count of a | |
const dimCount = a.length / 2 | |
// Create a list of all axes | |
let axes = [...(new Array(dimCount))].map((_, i) => i) | |
// Initialize | |
const result = [...(new Array(dimCount))] | |
// Calculate the deltas[n] between the adjecent sides of a[n] and b[n] | |
const deltas = [...(new Array(dimCount))].map((_, i) => { | |
if(a[i] < b[i]) { | |
return (b[i] - (b[dimCount+i] / 2)) - (a[i] + (a[dimCount+i] / 2)) | |
} else { | |
return (b[i] + (b[dimCount+i] / 2)) - (a[i] - (a[dimCount+i] / 2)) | |
} | |
}) | |
// Calculate the ratios between deltas[n] and v[n] | |
const deltaRatios = [...(new Array(dimCount))].map((_, i) => v[i] == 0 ? 1 : (deltas[i] / v[i])) | |
while(axes.length > 0) { | |
let ca = axes[0] | |
for(let a of axes) { // Find the closest hit axis | |
if(deltaRatios[a] < deltaRatios[ca]) { | |
ca = a | |
} | |
} | |
// Remove the axis from the remaining axes | |
axes = axes.filter(s => s != ca) | |
const d = deltas[ca] // Delta of the current axis | |
// Check whether delta and velocity point in the same direction | |
// because otherwise they would drift away from each other | |
// and collision would be impossible | |
let canCollide = (d == 0) || (Math.sign(d) == Math.sign(v[ca])) | |
for(let ta = 0; ta < dimCount; ta++) { | |
if(ta == ca) | |
continue // Only check the other axes | |
if(!canCollide) | |
break | |
// If already calculated use the actual hit point, otherwise use the current ratio of the velocity of the axis | |
const td = (!axes.includes(ta)) ? result[ta] : (deltaRatios[ca] * v[ta]) | |
// Calculate the min's and max's of a and b on the axis | |
const aMin = a[ta] - (a[dimCount+ta] / 2) + td | |
const aMax = a[ta] + (a[dimCount+ta] / 2) + td | |
const bMin = b[ta] - (b[dimCount+ta] / 2) | |
const bMax = b[ta] + (b[dimCount+ta] / 2) | |
// Check whether a and b can hit on this axis | |
canCollide = | |
((aMin > bMin) && (aMin < bMax)) || | |
((aMax > bMin) && (aMax < bMax)) || | |
((aMin <= bMin) && (aMax >= bMax)) || | |
((aMin >= bMin) && (aMax <= bMax)) | |
; | |
} | |
// Calculate the possible motion for the current axis | |
result[ca] = canCollide ? (Math.min(Math.abs(v[ca]), Math.abs(d)) * Math.sign(v[ca])) : v[ca] | |
} | |
return result | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment