Remove unused duplicate functions
This commit is contained in:
@@ -198,17 +198,17 @@
|
||||
<br/>
|
||||
<span id="velocity" xmlns="http://www.w3.org/1999/xhtml">-,-</span> x,y velocity
|
||||
</div>
|
||||
<ul xmlns="http://www.w3.org/1999/xhtml">
|
||||
<li xmlns="http://www.w3.org/1999/xhtml">bounce from collisions</li>
|
||||
<li xmlns="http://www.w3.org/1999/xhtml">fall off screen after crash</li>
|
||||
<li xmlns="http://www.w3.org/1999/xhtml">make ship a helicopter</li>
|
||||
<li xmlns="http://www.w3.org/1999/xhtml">use paths for walls</li>
|
||||
<li xmlns="http://www.w3.org/1999/xhtml">stop reading data from elements</li>
|
||||
<li xmlns="http://www.w3.org/1999/xhtml">limited fuel</li>
|
||||
<li xmlns="http://www.w3.org/1999/xhtml">additional cannon firing modes</li>
|
||||
<li xmlns="http://www.w3.org/1999/xhtml">keep ship position at 0,0 actual</li>
|
||||
<li xmlns="http://www.w3.org/1999/xhtml">only start on movement not just any keypress</li>
|
||||
</ul>
|
||||
<!-- <ul xmlns="http://www.w3.org/1999/xhtml"> -->
|
||||
<!-- <li xmlns="http://www.w3.org/1999/xhtml">bounce from collisions</li> -->
|
||||
<!-- <li xmlns="http://www.w3.org/1999/xhtml">fall off screen after crash</li> -->
|
||||
<!-- <li xmlns="http://www.w3.org/1999/xhtml">make ship a helicopter</li> -->
|
||||
<!-- <li xmlns="http://www.w3.org/1999/xhtml">use paths for walls</li> -->
|
||||
<!-- <li xmlns="http://www.w3.org/1999/xhtml">stop reading data from elements</li> -->
|
||||
<!-- <li xmlns="http://www.w3.org/1999/xhtml">limited fuel</li> -->
|
||||
<!-- <li xmlns="http://www.w3.org/1999/xhtml">additional cannon firing modes</li> -->
|
||||
<!-- <li xmlns="http://www.w3.org/1999/xhtml">keep ship position at 0,0 actual</li> -->
|
||||
<!-- <li xmlns="http://www.w3.org/1999/xhtml">only start on movement not just any keypress</li> -->
|
||||
<!-- </ul> -->
|
||||
<pre id="debug" xmlns="http://www.w3.org/1999/xhtml"></pre>
|
||||
<div id="pointer" xmlns="http://www.w3.org/1999/xhtml">
|
||||
x: <span class="x" xmlns="http://www.w3.org/1999/xhtml">-</span>,
|
||||
@@ -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";
|
||||
|
||||
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 57 KiB |
Reference in New Issue
Block a user