Add side collision detection

This commit is contained in:
2025-12-19 12:22:24 -08:00
parent 8b89673b6f
commit 8705b5779d

View File

@@ -59,7 +59,7 @@
</g> </g>
</g> </g>
<polygon id="wall" points="-20,-20 -20,-30 30,-30 30,30 -20,30 -20,20 20,20 20,-20" /> <polygon id="wall" points="-20,-20 -20,-30 30,-30 30,30 -10,40 -20,30 20,20 20,-20" />
<!-- <rect id="rect1" x="30" y="30" width="20" height="20"/> --> <!-- <rect id="rect1" x="30" y="30" width="20" height="20"/> -->
<g id="lines"> <g id="lines">
</g> </g>
@@ -156,6 +156,7 @@
function updateTriangles([positionX, positionY]) { function updateTriangles([positionX, positionY]) {
const delim = ' '; const delim = ' ';
const className = 'clockwise-orientation'; const className = 'clockwise-orientation';
const visible = [];
triangles.forEach(t => { triangles.forEach(t => {
const attr = t.getAttribute('points').split(delim); const attr = t.getAttribute('points').split(delim);
@@ -174,11 +175,14 @@
} }
t.classList[cwOrientation ? "add" : "remove"](className); t.classList[cwOrientation ? "add" : "remove"](className);
if (cwOrientation) visible.push(t);
// i think i can also discard obtuse triangles? // i think i can also discard obtuse triangles?
// if all the triangles are obtuse, i only need to check the nearest corner for a collision // if all the triangles are obtuse, i only need to check the nearest corner for a collision
// otherwise, i need to check only the acute triangles // otherwise, i need to check only the acute triangles
}); });
return visible;
} }
const lines = lineContainer.querySelectorAll('line'); const lines = lineContainer.querySelectorAll('line');
@@ -286,6 +290,10 @@
animate(timestamp); animate(timestamp);
} }
function distance(x1, y1, x2, y2) {
return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
}
function animate(timestamp) { function animate(timestamp) {
const delta = timestamp - zero; const delta = timestamp - zero;
const elapsed = timestamp - previous; const elapsed = timestamp - previous;
@@ -294,11 +302,11 @@
if (delta >= 1000) { if (delta >= 1000) {
fps.innerText = frameCount; fps.innerText = frameCount;
info.innerText = `velocity ${velocity}\n` // info.innerText = `velocity ${velocity}\n`
+ 'bullets\nx\ty\tvx\tvy\n' // + 'bullets\nx\ty\tvx\tvy\n'
+ bullets.map(b => { // + bullets.map(b => {
return `${b.x.toFixed(2)}\t${b.y.toFixed(2)}\t${b.vx.toFixed(2)}\t${b.vy.toFixed(2)}`; // return `${b.x.toFixed(2)}\t${b.y.toFixed(2)}\t${b.vx.toFixed(2)}\t${b.vy.toFixed(2)}`;
}).join("\n"); // }).join("\n");
zero = timestamp; zero = timestamp;
frameCount = 0; frameCount = 0;
@@ -306,6 +314,7 @@
frameCount++; frameCount++;
} }
let degrees = getRotate(gun); let degrees = getRotate(gun);
if (rotate > 0) gun.style.transform = `rotate(${(+degrees + rotationSpeed * elapsed) % 360}deg)`; if (rotate > 0) gun.style.transform = `rotate(${(+degrees + rotationSpeed * elapsed) % 360}deg)`;
@@ -338,7 +347,26 @@
updateBullets(elapsed); updateBullets(elapsed);
// updateLines(position); // updateLines(position);
updateTriangles(position); const visibleTriangles = updateTriangles(position);
// 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');
// can do this after side collision detection // can do this after side collision detection
// const ts = updateTriangles(position); // const ts = updateTriangles(position);
@@ -359,7 +387,25 @@
return shipBody.isPointInFill(cornerPt); return shipBody.isPointInFill(cornerPt);
}); });
wall.setAttribute('fill', cornerCollision ? 'red' : 'black'); const PI = Math.PI / 2;
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 < PI && beta < PI;
return acute ? [...acc, hc] : acc;
}, []).some(h => h <= shipRadius);
wall.setAttribute('fill', cornerCollision || sideCollision ? 'red' : 'black');
hitbox.style.transform = `translate(${positionX}px, ${positionY}px)`; hitbox.style.transform = `translate(${positionX}px, ${positionY}px)`;
// if (+y < 200) // if (+y < 200)

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 17 KiB