Elite: fix for laser collisions
Ok. So here’s the revised collision detection code:
function processLaserHits(game: Game, resources: Resources) {
// all we are really interested in for deciding if a player has hit a ship is the intersection of the bounding
// box of the ship onto a 2d plane. To do this we take each face of the bounding box, discard the z, and look to see
// if our laser axis (represented by point [0,0]) falls within it by breaking the face into two and using
// barycentric co-ordinates to see if we are in the triangle
const hit = game.localBubble.ships.reduce((hit: ShipInstance | null, ship) => {
if (ship.position[2] > 0) return hit
if (hit !== null && hit.position[2] > ship.position[2]) return hit
const translatedBoundingBox = ship.boundingBox.map((v) => {
const v2 = vec3.add(vec3.create(), v, ship.position)
return vec2.fromValues(v2[0], v2[1])
})
// This depends very much on the order that the bounding box is created in
const faces = [
// front
[0, 1, 2, 3],
// back
[4, 5, 6, 7],
// left
[0, 3, 4, 7],
// right
[1, 2, 5, 6],
// top
[0, 1, 5, 6],
// bottom
[2, 3, 6, 7],
]
const testPoint = vec2.fromValues(0, 0)
for (let fi = 0; fi < faces.length; fi++) {
const face = faces[fi]
const quad = [
translatedBoundingBox[face[0]],
translatedBoundingBox[face[1]],
translatedBoundingBox[face[2]],
translatedBoundingBox[face[3]],
]
const triangles = createTrianglesFromQuad(quad)
if (isPointInTriangle(testPoint, triangles[0]) || isPointInTriangle(testPoint, triangles[1])) {
return ship
}
}
return hit
}, null)
if (hit === null) {
resources.soundEffects.playerLaserMiss()
} else {
hit.isDestroyed = true
resources.soundEffects.shipExplosion()
}
}
Its similar to the previous version but is based around hit detecting each face of the cube in XY space rather than trying to fit a quad around the bounding box (which actually makes no sense at all… what was I thinking, or dreaming!).
There’s definitely some scope for improvement in the above but it does, at least, work!