This commit is contained in:
2026-02-05 10:08:52 -08:00
parent 424cb0f150
commit 70f958606d
2 changed files with 3 additions and 108 deletions

View File

@@ -119,7 +119,3 @@ Delete your `.sitegen_cache` file.
* use sitecache with pandoc renderer * use sitecache with pandoc renderer
* draft documents * draft documents
* treesitter highlighting for moonscript * treesitter highlighting for moonscript
--
- Bounce off multiple simultaneous contacts

View File

@@ -217,8 +217,6 @@
</foreignObject> </foreignObject>
<script type="text/javascript">//<![CDATA[ <script type="text/javascript">//<![CDATA[
const zeroP = { x: 0, y: 0 };
// entities // entities
const Ships = [{ entity_id: "ship1" }]; const Ships = [{ entity_id: "ship1" }];
// const Walls = [{ entity_id: "wall_1" }, { entity_id: "wall_2" }]; // const Walls = [{ entity_id: "wall_1" }, { entity_id: "wall_2" }];
@@ -228,12 +226,6 @@ const Velocity = {};
const Position = {}; const Position = {};
const Acceleration = {}; const Acceleration = {};
// Ships.forEach(({ entity_id }) => {
// Acceleration[entity_id] = zeroP;
// Velocity[entity_id] = zeroP;
// Position[entity_id] = zeroP;
// });
// Points = { // Points = {
// "wall_1": "0,0 2,0 1,1", // "wall_1": "0,0 2,0 1,1",
// "wall_2": "0,0 -1,1 -2,0", // "wall_2": "0,0 -1,1 -2,0",
@@ -242,8 +234,6 @@ const Acceleration = {};
// systems // systems
const Move = (() => { const Move = (() => {
const metersPerMillisecond = 0.001; const metersPerMillisecond = 0.001;
// const expo = 1e15;
const expo = 1e8;
// Triangle has a clockwise orientation // Triangle has a clockwise orientation
function isClockwise([xa, ya], [xb, yb], [xc, yc]) { function isClockwise([xa, ya], [xb, yb], [xc, yc]) {
@@ -262,8 +252,6 @@ const Move = (() => {
// const det = subR(xba * yca, xca * yba); // const det = subR(xba * yca, xca * yba);
// console.log("dett", det, "edge", xa, ya, xb, yb, "position", xc, yc, "aaa"); // console.log("dett", det, "edge", xa, ya, xb, yb, "position", xc, yc, "aaa");
// const detEx = (xb*expo - xa*expo) * (yc*expo - ya*expo) - (xc*expo - xa*expo) * (yb*expo - ya*expo);
// (8.0046e+33) / 1e30 // (8.0046e+33) / 1e30
// -> 8004.599999999999 // -> 8004.599999999999
// 8.0046e+33 * 1e-30 // 8.0046e+33 * 1e-30
@@ -285,7 +273,6 @@ const Move = (() => {
// -0.574 * 1e11 // -0.574 * 1e11
// -57399999999.99999 // -57399999999.99999
// if det == 0, that means we are in contact with that edge // if det == 0, that means we are in contact with that edge
return det < 0; return det < 0;
} }
@@ -723,7 +710,6 @@ const Move = (() => {
const { x: vx, y: vy } = Velocity[entity_id]; const { x: vx, y: vy } = Velocity[entity_id];
const { x: ax, y: ay } = Acceleration[entity_id]; const { x: ax, y: ay } = Acceleration[entity_id];
const vr = { const vr = {
x: Math.round(vx * 100 + ax * 100) / 100, x: Math.round(vx * 100 + ax * 100) / 100,
y: Math.round(vy * 100 + ay * 100) / 100 y: Math.round(vy * 100 + ay * 100) / 100
@@ -741,20 +727,11 @@ const Move = (() => {
// console.log("v", v, "ax", ax, "ay", ay); // console.log("v", v, "ax", ax, "ay", ay);
// v.x = +v.x.toPrecision(13);
// v.y = +v.y.toPrecision(13);
const exp = 1e4
const p = { const p = {
// x: px + elapsed * v.x * metersPerMillisecond, // x: px + elapsed * v.x * metersPerMillisecond,
// y: py + elapsed * v.y * metersPerMillisecond // y: py + elapsed * v.y * metersPerMillisecond
x: Math.round((px + elapsed * v.x * metersPerMillisecond) * 100) / 100, x: Math.round((px + elapsed * v.x * metersPerMillisecond) * 100) / 100,
y: Math.round((py + elapsed * v.y * metersPerMillisecond) * 100) / 100, y: Math.round((py + elapsed * v.y * metersPerMillisecond) * 100) / 100,
// x: (px * exp + elapsed * 1000 * v.x / 1000) / exp,
// y: (py * exp + elapsed * 1000 * v.y / 1000) / exp
}; };
// console.log("----------elapsed", elapsed) // console.log("----------elapsed", elapsed)
@@ -763,7 +740,6 @@ const Move = (() => {
// p.x = +p.x.toPrecision(13); // p.x = +p.x.toPrecision(13);
// p.y = +p.y.toPrecision(13); // p.y = +p.y.toPrecision(13);
const contacts = detectContacts([px, py], p, v, s.radius, map, false); const contacts = detectContacts([px, py], p, v, s.radius, map, false);
if (contacts.length !== 0) { if (contacts.length !== 0) {
@@ -795,7 +771,6 @@ const Move = (() => {
Position[entity_id] = cornerContactPosition(p.x, p.y, px, py, contact.corner, s.radius); Position[entity_id] = cornerContactPosition(p.x, p.y, px, py, contact.corner, s.radius);
} else if (contact.edge) { } else if (contact.edge) {
// if (isLandable(contact.edge) && s.gearDown) s.isLanded = true; // if (isLandable(contact.edge) && s.gearDown) s.isLanded = true;
// const accVect = vector(ax, ay);
const rise = contact.edge.yb-contact.edge.ya; const rise = contact.edge.yb-contact.edge.ya;
const run = contact.edge.xb-contact.edge.xa; const run = contact.edge.xb-contact.edge.xa;
const edgeNrmlVect = vector(rise, -run); const edgeNrmlVect = vector(rise, -run);
@@ -803,26 +778,18 @@ const Move = (() => {
const velocityVect = vector(v.x, v.y); const velocityVect = vector(v.x, v.y);
const vDotn = edgeNrmlVect.x * velocityVect.x + edgeNrmlVect.y * velocityVect.y; const vDotn = edgeNrmlVect.x * velocityVect.x + edgeNrmlVect.y * velocityVect.y;
// const aDotn = edgeNrmlVect.x * accVect.x + edgeNrmlVect.y * accVect.y;
const denom = edgeNrmlVect.x ** 2 + edgeNrmlVect.y ** 2; const denom = edgeNrmlVect.x ** 2 + edgeNrmlVect.y ** 2;
const pVect = { const pVect = {
x: vDotn / denom * edgeNrmlVect.x, x: vDotn / denom * edgeNrmlVect.x,
y: vDotn / denom * edgeNrmlVect.y y: vDotn / denom * edgeNrmlVect.y
}; };
// (-1.2*100 - -14.8*100)/100
// console.log("vDotn", vDotn); // console.log("vDotn", vDotn);
// console.log("denom", denom); // console.log("denom", denom);
// console.log("pVect", pVect); // console.log("pVect", pVect);
// const aVect = {
// x: aDotn / denom * edgeNrmlVect.x,
// y: aDotn / denom * edgeNrmlVect.y
// };
const reverseP = { x: -pVect.x, y: -pVect.y }; const reverseP = { x: -pVect.x, y: -pVect.y };
// const reverseA = { x: -aVect.x, y: -aVect.y };
// add reverseP and v vectors together and a vector // add reverseP and v vectors together and a vector
const prVonNx = Math.round(reverseP.x*100 + v.x*100)/100; const prVonNx = Math.round(reverseP.x*100 + v.x*100)/100;
@@ -849,17 +816,13 @@ const Move = (() => {
// console.log("intended next position", p); // console.log("intended next position", p);
drawCircle(p.x, p.y, "red"); drawCircle(p.x, p.y, "red");
// const newV = {
// x: vx > 0 && vx + ax <= 0 ? 0 : vx + ax,
// y: vy > 0 && vy + ay <= 0 ? 0 : vy + ay
// };
let newP = { let newP = {
// x: contact.position.x + elapsed * prVonNx * metersPerMillisecond, // x: contact.position.x + elapsed * prVonNx * metersPerMillisecond,
// y: contact.position.y + elapsed * prVonNy * metersPerMillisecond // y: contact.position.y + elapsed * prVonNy * metersPerMillisecond
x: Math.round((contact.position.x + elapsed * prVonNx * metersPerMillisecond) * 100) / 100, x: Math.round((contact.position.x + elapsed * prVonNx * metersPerMillisecond) * 100) / 100,
y: Math.round((contact.position.y + elapsed * prVonNy * metersPerMillisecond) * 100) / 100, y: Math.round((contact.position.y + elapsed * prVonNy * metersPerMillisecond) * 100) / 100,
}; };
// console.log("calculated next position", newP, "dett"); // console.log("calculated next position", newP, "dett");
let isC = isClockwise([contact.edge.xa, contact.edge.ya], [contact.edge.xb, contact.edge.yb], [newP.x, newP.y]); let isC = isClockwise([contact.edge.xa, contact.edge.ya], [contact.edge.xb, contact.edge.yb], [newP.x, newP.y]);
// console.log("is calculated next position clockwise with current contact", isC, "aaa"); // console.log("is calculated next position clockwise with current contact", isC, "aaa");
@@ -872,8 +835,7 @@ const Move = (() => {
// const npVect = { x: newP.x - run, y: newP.y - rise }; // const npVect = { x: newP.x - run, y: newP.y - rise };
const npVect = { x: newP.x - contact.edge.xa, y: newP.y - contact.edge.ya }; const npVect = { x: newP.x - contact.edge.xa, y: newP.y - contact.edge.ya };
drawLine(contact.edge.xa, contact.edge.ya, contact.edge.xa + npVect.x, contact.edge.ya + npVect.y); // drawLine(contact.edge.xa, contact.edge.ya, contact.edge.xa + npVect.x, contact.edge.ya + npVect.y);
const projection = ({ of, onto }) => { const projection = ({ of, onto }) => {
const ofDotOnto = onto.x * of.x + onto.y * of.y; const ofDotOnto = onto.x * of.x + onto.y * of.y;
@@ -891,70 +853,14 @@ const Move = (() => {
projNpOntoEdge.x = projNpOntoEdge.x + contact.edge.xa; projNpOntoEdge.x = projNpOntoEdge.x + contact.edge.xa;
projNpOntoEdge.y = projNpOntoEdge.y + contact.edge.ya; projNpOntoEdge.y = projNpOntoEdge.y + contact.edge.ya;
// can I reflect the calculated next position across the edge line?
const m = rise / run;
const c = (contact.edge.xb*contact.edge.ya-contact.edge.xa*contact.edge.yb) / (contact.edge.xb-contact.edge.xa);
const d = (newP.x + (newP.y - c)*m)/(1+m**2);
const refP = {
x: 2*d - newP.x,
y: 2*d*m - newP.y + 2*c
};
// console.log("reflection before rounding", refP, "aaa");
// refP.x = Math.round(refP.x * 100) / 100;
// refP.y = Math.round(refP.y * 100) / 100;
// shouldnt change isClockwise if isAcute isn't also changing // shouldnt change isClockwise if isAcute isn't also changing
// if we go from clockwise to not clockwise without changing acuteness, // if we go from clockwise to not clockwise without changing acuteness,
// that means we went through a wall // that means we went through a wall
// if (!isC && isA) newP = refP;
if (!isC && isA) newP = projNpOntoEdge; if (!isC && isA) newP = projNpOntoEdge;
// console.log("reflection", refP, projNpOntoEdge, "aaa");
isC = isClockwise([contact.edge.xa, contact.edge.ya], [contact.edge.xb, contact.edge.yb], [refP.x, refP.y]);
// console.log("is reflected position clockwise with current contact", isC, "aaa");
isA = isAcute([contact.edge.xa, contact.edge.ya], [contact.edge.xb, contact.edge.yb], [refP.x, refP.y]);
// console.log("is reflected position acute with current contact", isA, "aaa");
// how close can you come to an edge without being on it?
const inWall = contact.wall.node.isPointInFill(newP);
// console.log("is our calculated next position inside current edge's wall?", inWall, "dett");
// if an edge passes through a point, is that point in the wall's fill? yes // if an edge passes through a point, is that point in the wall's fill? yes
// so touching a wall is technically being in its fill // so touching a wall is technically being in its fill
const lnIntxnFromTwoPts = (ln1, ln2) => {
const { xa: x1, ya: y1, xb: x2, yb: y2 } = ln1;
const { xa: x3, ya: y3, xb: x4, yb: y4 } = ln2;
const denom = (x1-x2)*(y3-y4)-(y1-y2)*(x3-x4)
return {
x: ((x1*y2-y1*x2)*(x3-x4)-(x1-x2)*(x3*y4-y3*x4)) / denom,
y: ((x1*y2-y1*x2)*(y3-y4)-(y1-y2)*(x3*y4-y3*x4)) / denom
};
}
// const rise = contact.edge.yb - contact.edge.ya;
// const run = constact.edge.xb - contact.edge.xa;
// const p_new = lnIntxnFromTwoPts(contact.edge, { xa: newP.x, ya: newP.y, xb: newP.x + rise, yb: newP.y - run });
// newP = lnIntxnFromTwoPts(contact.edge, { xa: newP.x, ya: newP.y, xb: newP.x + rise, yb: newP.y - run });
// const isCw = isClockwise([contact.edge.xa, contact.edge.ya], [contact.edge.xb, contact.edge.yb], [newP.x, newP.y]);
// const lnD = distance(contact.position.x, contact.position.y, newP.x, newP.y);
const lnD = distance(contact.edge.xa, contact.edge.ya, newP.x, newP.y);
const ln = document.createElementNS(namespaceURIsvg, 'line');
ln.setAttribute('x1', contact.edge.xa);
ln.setAttribute('y1', contact.edge.ya);
ln.setAttribute('x2', newP.x);
ln.setAttribute('y2', newP.y);
// newP = ln.getPointAtLength(lnD);
// container.appendChild(el);
drawCircle(newP.x, newP.y, "black"); drawCircle(newP.x, newP.y, "black");
Position[entity_id] = newP; Position[entity_id] = newP;
@@ -1493,9 +1399,6 @@ function firstFrame(timestamp) {
function animate(timestamp) { function animate(timestamp) {
// console.log("----------animate timestamp", timestamp, "previous", previous); // console.log("----------animate timestamp", timestamp, "previous", previous);
// 2064.26 * 1000 - 2036.26 * 1000
// 28000.000000000233
// const elapsed = (timestamp * 1000 - previous * 1000) / 1000; // const elapsed = (timestamp * 1000 - previous * 1000) / 1000;
const elapsed = (Math.round(timestamp * 1000) - Math.round(previous * 1000)) / 1000; const elapsed = (Math.round(timestamp * 1000) - Math.round(previous * 1000)) / 1000;
const delta = (timestamp * 1000 - zero * 1000) / 1000; const delta = (timestamp * 1000 - zero * 1000) / 1000;
@@ -1516,20 +1419,16 @@ function animate(timestamp) {
frameCount++; frameCount++;
} }
// s.node.style.transform = `translate(${s.position.x}px, ${s.position.y}px)`; // s.node.style.transform = `translate(${s.position.x}px, ${s.position.y}px)`;
// Move.update(Ships[0], elapsed); // Move.update(Ships[0], elapsed);
Ships.forEach(({ entity_id }) => { Ships.forEach(({ entity_id }) => {
// Acceleration[entity_id] = zeroP;
// Velocity[entity_id] = zeroP;
// Position[entity_id] = zeroP;
Move.update({ entity_id }, elapsed); Move.update({ entity_id }, elapsed);
}); });
let newPos = updateShip(s, elapsed); let newPos = updateShip(s, elapsed);
newPos = Position[Ships[0].entity_id]; newPos = Position[Ships[0].entity_id];
newVel = Velocity[Ships[0].entity_id]; let newVel = Velocity[Ships[0].entity_id];
s.node.style.transform = `translate(${newPos.x}px, ${newPos.y}px)`; s.node.style.transform = `translate(${newPos.x}px, ${newPos.y}px)`;
positionEl.innerText = `${newPos.x},${newPos.y}`; positionEl.innerText = `${newPos.x},${newPos.y}`;

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 53 KiB