diff --git a/html/images/space.svg b/html/images/space.svg
index 51c4312..ca6da7f 100644
--- a/html/images/space.svg
+++ b/html/images/space.svg
@@ -198,17 +198,17 @@
-,- x,y velocity
-
- - bounce from collisions
- - fall off screen after crash
- - make ship a helicopter
- - use paths for walls
- - stop reading data from elements
- - limited fuel
- - additional cannon firing modes
- - keep ship position at 0,0 actual
- - only start on movement not just any keypress
-
+
+
+
+
+
+
+
+
+
+
+
x: -,
@@ -1090,14 +1090,6 @@ function init() {
time.innerText = "0";
}
-
-// const b = map.edges.map(({ edge }) => getEdgeCollisionBoundary(edge, shipRadius));
-// b.forEach(b => drawLine(b.xa, b.ya, b.xb, b.yb, "orange"));
-
-function distance(x1, y1, x2, y2) {
- return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
-}
-
function drawTriangles(container, walls, [positionX, positionY]) {
walls.forEach(pts =>
pts.forEach(([[x1, y1], [x2, y2]]) => {
@@ -1109,93 +1101,6 @@ function drawTriangles(container, walls, [positionX, positionY]) {
);
}
-// Triangle has a clockwise orientation
-function isClockwise([xa, ya], [xb, yb], [xc, yc]) {
- // https://en.wikipedia.org/wiki/Curve_orientation#Practical_considerations
- // Determinant for a convex polygon
- const det = (+xb - +xa) * (+yc - +ya) - (+xc - +xa) * (+yb - +ya);
- return det < 0;
-}
-
-function isAcute([xa, ya], [xb, yb], [xc, yc]) {
- const da = distance(xa, ya, xc, yc);
- const db = distance(xb, yb, xc, yc);
- const dc = distance(xa, ya, xb, yb);
-
- // https://en.wikipedia.org/wiki/Law_of_cosines
- // Solve for angles alpha and beta with inverse cosine (arccosine)
- 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));
-
- return alpha < halfPi && beta < halfPi;
-}
-
-function getForwardEdges(edges, { x, y }) {
- return edges.filter(({ edge: { xa, ya, xb, yb } }) =>
- isClockwise([xa, ya], [xb, yb], [x, y]) && isAcute([xa, ya], [xb, yb], [x, y]));
-}
-
-function getForwardCorners(corners, position, velocity) {
- const { x: x1, y: y1 } = position;
- const { x: x2, y: y2 } = velocity;
-
- const { x: vx, y: vy } = velocity;
-
- let perppts = {};
-
- if (vx === 0 && vy === 0) {
- // none
- } else if (vx === 0 && vy > 0) {
- perppts = { a: { x: x1 - 1, y: y1 }, b: { x: x1 + 1, y: y1 }};
- } else if (vx === 0 && vy < 0) {
- perppts = { a: { x: x1 + 1, y: y1 }, b: { x: x1 - 1, y: y1 }};
- } else if (vy === 0 && vx > 0) {
- perppts = { a: { x: x1, y: y1 + 1 }, b: { x: x1, y: y1 - 1 }};
- } else if (vy === 0 && vx < 0) {
- perppts = { a: { x: x1, y: y1 - 1 }, b: { x: x1, y: y1 + 1 }};
- } else if (vy > 0 && vx > 0) {
- const vslope = vy / vx;
- const pslope = 1 / -vslope;
- // Point-slope line equation
- const pya = pslope * (x1 - 1) - pslope * x1 + y1;
- const pyb = pslope * (x1 + 1) - pslope * x1 + y1;
-
- perppts = { a: { x: x1 - 1, y: pya }, b: { x: x1 + 1, y: pyb }};
- } else if (vy > 0 && vx < 0) {
- const vslope = vy / vx;
- const pslope = 1 / -vslope;
- const pya = pslope * (x1 - 1) - pslope * x1 + y1;
- const pyb = pslope * (x1 + 1) - pslope * x1 + y1;
-
- perppts = { a: { x: x1 - 1, y: pya }, b: { x: x1 + 1, y: pyb }};
- } else if (vy < 0 && vx > 0) {
- const vslope = vy / vx;
- const pslope = 1 / -vslope;
- const pya = pslope * (x1 + 1) - pslope * x1 + y1;
- const pyb = pslope * (x1 - 1) - pslope * x1 + y1;
-
- perppts = { a: { x: x1 + 1, y: pya }, b: { x: x1 - 1, y: pyb }};
- } else if (vy < 0 && vx < 0) {
- const vslope = vy / vx;
- const pslope = 1 / -vslope;
- const pya = pslope * (x1 + 1) - pslope * x1 + y1;
- const pyb = pslope * (x1 - 1) - pslope * x1 + y1;
-
- perppts = { a: { x: x1 + 1, y: pya }, b: { x: x1 - 1, y: pyb }};
- } else {
- //
- }
-
- const { a, b } = perppts;
- // if (a && b) drawLine(a.x, a.y, b.x, b.y);
-
- return corners.filter(({ corner: c }) => {
- if (!a || !b) return;
- const det = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
- return det > 0;
- });
-}
-
function updateTriangles([positionX, positionY]) {
const delim = ' ';
const className = 'clockwise-orientation';
@@ -1322,25 +1227,6 @@ function fireBullet(position, degrees) {
setTimeout(() => appended.classList.add('fade'), 1000);
}
-function perpIntxn(baseSlope, xa, ya, xc, yc) {
- let isx, isy;
-
- // base is vertical
- if (baseSlope === -Infinity || baseSlope === Infinity) {
- isx = xa;
- isy = yc;
- } else if (baseSlope === 0) { // base is horizontal
- isx = xc;
- isy = ya;
- } else {
- const altitudeSlope = 1 / -baseSlope;
- isx = (-altitudeSlope * xc + yc + baseSlope * xa - ya) / (baseSlope - altitudeSlope);
- isy = altitudeSlope * isx - altitudeSlope * xc + yc;
- }
-
- return { x: isx, y: isy };
-}
-
function drawLine(xa, ya, xb, yb, color = "black") {
const el = document.createElementNS(namespaceURIsvg, 'line');
el.setAttribute('x1', xa);
@@ -1369,142 +1255,11 @@ function drawCircle(cx, cy, color = "black", r = 1) {
return el;
}
-function slope({ xa, ya, xb, yb }) {
- return (yb - ya) / (xb - xa);
-}
-
function isLandable(edge) {
return edge.xa < edge.xb && edge.ya === edge.yb;
// return Object.is(slope(edge), +0);
}
-function getEdgeCollisionBoundary(edge, dist) {
- const { xa, ya, xb, yb } = edge;
- const length = distance(xa, ya, xb, yb);
- const rise = yb - ya;
- const run = xb - xa;
- const riol = rise / length * dist;
- const ruol = run / length * dist;
-
- return { xa: xa + riol, ya: ya - ruol, xb: xb + riol, yb: yb - ruol};
-}
-
-function detectEdgeCollision([xc, yc], [x, y], radius, gearDown) {
-
- return (collision) => {
- if (xc === x && yc === y) return;
- const { edge, wall } = collision;
- const dist = edge.xa < edge.xb && edge.ya === edge.yb && gearDown ? radius + 1.5 : radius;
- const edgeSeg = getEdgeCollisionBoundary(edge, dist);
- const positionSeg = { xa: x, ya: y, xb: xc, yb: yc };
-
- const { xa: x1, ya: y1, xb: x2, yb: y2 } = positionSeg;
- const { xa: x3, ya: y3, xb: x4, yb: y4 } = edgeSeg;
- // const { xa: x3, ya: y3, xb: x4, yb: y4 } = edge;
-
- // https://en.wikipedia.org/wiki/Intersection_(geometry)#Two_line_segments
- // https://en.wikipedia.org/wiki/Cramer%27s_rule#Explicit_formulas_for_small_systems
- // const denom = +((x2-x1)*(y4-y3)-(x4-x3)*(y2-y1)).toPrecision(13);
- const x21 = +(x2-x1).toPrecision(13);
- const y43 = +(y4-y3).toPrecision(13);
- const x43 = +(x4-x3).toPrecision(13);
- const y21 = +(y2-y1).toPrecision(13);
- const denom = +(x21*y43-x43*y21).toPrecision(13);
- const x31 = +(x3-x1).toPrecision(13);
- const y31 = +(y3-y1).toPrecision(13);
-
- const s = +(+(x31*y43-x43*y31).toPrecision(13) / denom).toPrecision(13);
- const t = +(-(x21*y31-x31*y21).toPrecision(13) / denom).toPrecision(13);
-
- // const s = +(((x3-x1)*(y4-y3)-(x4-x3)*(y3-y1))/denom).toPrecision(13);
- // const t = +(-((x2-x1)*(y3-y1)-(x3-x1)*(y2-y1))/denom).toPrecision(13);
-
-
- if (s >= 0 && s <= 1 && t >= 0 && t <= 1) {
-
- const xs = (x1 + s * +(x2 - x1).toPrecision(13));
- const ys = (y1 + s * +(y2 - y1).toPrecision(13));
- collision.position = { x: +xs.toPrecision(13), y: +ys.toPrecision(13) };
-
- return true;
- }
- // return roundedS >= 0 && roundedS <= 1 && roundedT >= 0 && roundedT <= 1;
- return;
- };
-}
-
-function detectCornerCollision([xc, yc], [x, y], radius) {
- return c => {
- if (xc === x && yc === y) return;
-
- const d = distance(c.corner.x, c.corner.y, xc, yc);
-
- if (d <= radius) return true;
-
- const positionSeg = { xa: xc, ya: yc, xb: x, yb: y };
- const posNormIntxn = perpIntxn(slope(positionSeg), x, y, c.corner.x, c.corner.y);
- const cornerSeg = { xa: c.corner.x, ya: c.corner.y, xb: posNormIntxn.x, yb: posNormIntxn.y };
-
- const { x: x0, y: y0 } = c.corner;
- const { xa: x1, ya: y1, xb: x2, yb: y2 } = positionSeg;
- const { xa: x3, ya: y3, xb: x4, yb: y4 } = cornerSeg;
-
- // https://en.wikipedia.org/wiki/Intersection_(geometry)#Two_line_segments
- // https://en.wikipedia.org/wiki/Cramer%27s_rule#Explicit_formulas_for_small_systems
- const s = ((x3-x1)*(y4-y3)-(x4-x3)*(y3-y1))/((x2-x1)*(y4-y3)-(x4-x3)*(y2-y1));
- const t = -((x2-x1)*(y3-y1)-(x3-x1)*(y2-y1))/((x2-x1)*(y4-y3)-(x4-x3)*(y2-y1));
- const roundedT = +t.toFixed(2);
-
- if (s >= 0 && roundedT <= 1) {
- const xs = (x1 + s * (x2 - x1));
- const ys = (y1 + s * (y2 - y1));
- const xt = (x3 + roundedT * (x4 - x3));
- const yt = (y3 + roundedT * (y4 - y3));
- // [xs, ys] and [xt, yt] should be equal ([xs, ys] === [xy, yt])
- // (...or about equal, notwithstanding rounding errors)
- const sCollisionPt = [xs, ys];
- const tCollisionPt = [xt, yt];
- // drawCircle(posNormIntxn.x, posNormIntxn.y, "red");
- // drawCircle(...tCollisionPt, "blue");
- }
-
- return s >= 0 && roundedT <= 1;
- };
-}
-
-function detectCollision(currentPos, intendedPos, velocity, radius, { edges, corners }, gearDown) {
- const { x: xc, y: yc } = intendedPos;
- const [x, y] = currentPos;
- // edges oriented clockwise with ship
- const fwdEdges = getForwardEdges(edges, { x, y })
- const edgeColl = fwdEdges.find(detectEdgeCollision([xc, yc], [x, y], radius, gearDown));
-
- if (edgeColl) return edgeColl;
-
- // corners ahead of ship
- const fwdCorners = getForwardCorners(corners, { x, y }, velocity);
- const cornersInPath = fwdCorners.filter(withinCollisionDistance({ x, y }, velocity, radius));
- const cornerColl = cornersInPath.find(detectCornerCollision([xc, yc], [x, y], radius));
-
- if (cornerColl) return cornerColl;
-}
-
-function withinCollisionDistance({ x: x1, y: y1 }, { x: x2, y: y2 }, distance) {
- const diffx = x2;
- const diffy = y2;
- const detv = x2 * y1 - y2 * x1;
- const dv = Math.sqrt(diffy ** 2 + diffx ** 2);
- const slopev = slope({ xa: x1, ya: y1, xb: x1 + x2, yb: y1 + y2 });
-
- return ({ corner: { x: x0, y: y0 }}) => {
- const velNormIntxn = perpIntxn(slopev, x1, y1, x0, y0);
- const dx = Math.max(x0, velNormIntxn.x) - Math.min(x0, velNormIntxn.x);
- const dy = Math.max(y0, velNormIntxn.y) - Math.min(y0, velNormIntxn.y);
- const d = Math.sqrt(dy ** 2 + dx ** 2);
- return d <= distance;
- };
-}
-
function cornerContactPosition(xc, yc, x, y, corner, cLength) {
const positionSeg = { xa: xc, ya: yc, xb: x, yb: y };
const posNormIntxn = perpIntxn(slope(positionSeg), x, y, corner.x, corner.y);
@@ -1628,7 +1383,7 @@ function updateShip(s, elapsed) {
s.degrees = degrees + dDelta;
current = s.collision;
- s.collision = detectCollision([px, py], p, s.velocity, s.radius, map, s.gearDown);
+ // s.collision = detectCollision([px, py], p, s.velocity, s.radius, map, s.gearDown);
// if (!current && s.collision) console.log("COLLISION", s.collision);
legs.style.display = s.gearDown ? "initial" : "none";