From 50a20982a4d9c0e4c8016b1eeb81667f07d2c23d Mon Sep 17 00:00:00 2001 From: Catalin Constantin Mititiuc Date: Sat, 20 Dec 2025 08:40:41 -0800 Subject: [PATCH] Move collision detection code into its own function --- html/images/space.svg | 97 ++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 56 deletions(-) diff --git a/html/images/space.svg b/html/images/space.svg index 0071be3..c1f2192 100644 --- a/html/images/space.svg +++ b/html/images/space.svg @@ -314,6 +314,44 @@ }); } + function detectCollision(points, visibleTriangles) { + const cornerCollision = points.some(([x, y]) => { + cornerPt.x = x - positionX; + cornerPt.y = y - positionY; + + return shipBody.isPointInFill(cornerPt); + }); + + const shipRadius = 5; + const sideCollision = [...visibleTriangles].reduce((acc, t) => { + const [[ax, ay], [bx, by], [shipx, shipy]] = + t.getAttribute('points').split(' ').map(n => n.split(',').map(n => +n)); + + const da = distance(ax, ay, shipx, shipy); + const db = distance(bx, by, shipx, shipy); + // TODO: calculate this one ahead of time + const dc = distance(ax, ay, bx, by); + + // https://en.wikipedia.org/wiki/Altitude_(triangle)#Altitude_in_terms_of_the_sides + // Find altitude of side c (the base) + const s = (1 / 2) * (da + db + dc); + const hc = (2 / dc) * Math.sqrt(s * (s - da) * (s - db) * (s - dc)); + + // https://en.wikipedia.org/wiki/Law_of_cosines + // Solve for angles alpha and beta with inverse cosine (arccosine) function + const alpha = Math.acos((db**2 + dc**2 - da**2) / (2 * db * dc)); + const beta = Math.acos((da**2 + dc**2 - db**2) / (2 * da * dc)); + + // Is acute if both angles are < 90 degrees + // TODO: what about right triangles? + const isAcute = alpha < halfPi && beta < halfPi; + + return isAcute ? [...acc, hc] : acc; + }, []).some(h => h <= shipRadius); + + return cornerCollision || sideCollision; + } + requestAnimationFrame(firstFrame); let start; @@ -408,65 +446,12 @@ drawEdges(trianglePts); } - // info.innerText = [...visibleTriangles].map(t => { - // const [[ax, ay], [bx, by], [shipx, shipy]] = - // t.getAttribute('points').split(' ').map(n => n.split(',').map(n => +n)); - // - // const da = distance(ax, ay, shipx, shipy); - // const db = distance(bx, by, shipx, shipy); - // const dc = distance(ax, ay, bx, by); - // const s = (1 / 2) * (da + db + dc); - // const hc = (2 / dc) * Math.sqrt(s * (s - da) * (s - db) * (s - dc)); - // - // const alpha = Math.acos((db**2 + dc**2 - da**2) / (2 * db * dc)); - // const beta = Math.acos((da**2 + dc**2 - db**2) / (2 * da * dc)); - // - // const PI = Math.PI / 2; - // const acute = alpha < PI && beta < PI; - // - // return `${da.toFixed(2)} ${db.toFixed(2)} ${dc.toFixed(2)} ${hc.toFixed(2)} ${alpha.toFixed(2)} ${beta.toFixed(2)}`; - // }).join('\n'); + const collision = detectCollision(points, visibleTriangles); - // can do this after side collision detection - // const ts = updateTriangles(position); - // const corners = ts.reduce((acc, t) => { - // const [a, b,] = t.getAttribute('points').split(' '); - // // return p.map(t => t.split(',')); - // // acc.push(a); - // // acc.push(b); - // return [a, b, ...acc]; - // }, []); - // - // const uniqueCorners = [...new Set(corners)].map(n => n.split(',').map(n => +n)); - - const cornerCollision = points.some(([x, y]) => { - cornerPt.x = x - positionX; - cornerPt.y = y - positionY; - - return shipBody.isPointInFill(cornerPt); - }); - - const shipRadius = 5; - const sideCollision = [...visibleTriangles].reduce((acc, t) => { - const [[ax, ay], [bx, by], [shipx, shipy]] = - t.getAttribute('points').split(' ').map(n => n.split(',').map(n => +n)); - - const da = distance(ax, ay, shipx, shipy); - const db = distance(bx, by, shipx, shipy); - const dc = distance(ax, ay, bx, by); - const s = (1 / 2) * (da + db + dc); - const hc = (2 / dc) * Math.sqrt(s * (s - da) * (s - db) * (s - dc)); - const alpha = Math.acos((db**2 + dc**2 - da**2) / (2 * db * dc)); - const beta = Math.acos((da**2 + dc**2 - db**2) / (2 * da * dc)); - const acute = alpha < halfPi && beta < halfPi; - - return acute ? [...acc, hc] : acc; - }, []).some(h => h <= shipRadius); - - wall.setAttribute('fill', cornerCollision || sideCollision ? 'red' : 'black'); + wall.setAttribute('fill', collision ? 'red' : 'black'); hitbox.style.transform = `translate(${positionX}px, ${positionY}px)`; - if (cornerCollision || sideCollision) { + if (collision) { // restart game zeroForTimer = timestamp; restart = true;