Changes
3 changed files (+59/-71)
-
-
@@ -1,19 +1,17 @@"use strict"; // See script.ts for original source code // Compile using tsc script.ts --lib esnext,dom --alwaysStrict // Inject SVG into DOM synchronously because we can't access the DOM of SVGs inside img tags document.querySelectorAll("svg").forEach(function (svg) { var req = new XMLHttpRequest(); let req = new XMLHttpRequest(); req.open("GET", svg.id + ".svg", false); req.send(); svg.outerHTML = req.responseText; }); var rad = 10; // Stroke radius var A = new Array(); // Objects var idcnt = 0; var ix = 0; var iy = 0; var ny = 0; const rad = 10; // Stroke radius let A = new Array(); // Objects let idcnt = 0; let ix = 0; let iy = 0; let ny = 0; document.querySelectorAll("svg").forEach(function (svg) { // Position objects so they aren't overlapping if (ix + svg.width.baseVal.value > window.innerWidth) {
-
@@ -26,8 +24,8 @@ svg.style.top = iy + "px";ix += svg.width.baseVal.value; ny = Math.max(svg.height.baseVal.value, ny); svg.id = String(idcnt++); var rect = svg.getBoundingClientRect(); var a = { const rect = svg.getBoundingClientRect(); const a = { id: svg.id, p: [], cm: svg.createSVGPoint(),
-
@@ -43,9 +41,9 @@ r: 0}; svg.querySelectorAll("path").forEach(function (path) { // Get circles on path for collision checking var num = Math.floor(path.getTotalLength() * 2 / rad); for (var i = 0; i <= num; i++) { var p = path.getPointAtLength(i / num * path.getTotalLength()); const num = Math.floor(path.getTotalLength() * 2 / rad); for (let i = 0; i <= num; i++) { const p = path.getPointAtLength(i / num * path.getTotalLength()); a.cm.x += p.x; a.cm.y += p.y; a.p.push(p);
-
@@ -63,32 +61,27 @@ a.cm.y /= a.p.length;// Change origin to center of mass a.x += a.cm.x; a.y += a.cm.y; for (var _i = 0, _a = a.p; _i < _a.length; _i++) { var p = _a[_i]; for (const p of a.p) { p.x -= a.cm.x; p.y -= a.cm.y; } svg.style.transformOrigin = a.cm.x + "px " + a.cm.y + "px"; a.m = a.p.length; for (var _b = 0, _c = a.p; _b < _c.length; _b++) { var p = _c[_b]; a.mi += Math.pow(p.x, 2) + Math.pow(p.y, 2); } for (var _d = 0, _e = a.p; _d < _e.length; _d++) { var p = _e[_d]; a.r = Math.max(Math.sqrt(Math.pow(p.x, 2) + Math.pow(p.y, 2)), a.r); } for (const p of a.p) a.mi += p.x ** 2 + p.y ** 2; for (const p of a.p) a.r = Math.max(Math.sqrt(p.x ** 2 + p.y ** 2), a.r); A.push(a); }); // Actual position of p in object a function rot(a, p) { var c = Math.cos(a.th); var s = Math.sin(a.th); const c = Math.cos(a.th); const s = Math.sin(a.th); return { x: a.x + p.x * c - p.y * s, y: a.y + p.x * s + p.y * c }; } // Distance squared between a and b function ds(a, b) { return Math.pow((a.x - b.x), 2) + Math.pow((a.y - b.y), 2); return (a.x - b.x) ** 2 + (a.y - b.y) ** 2; } // Cross product function cr(a, b) {
-
@@ -102,11 +95,11 @@ // https://physics.stackexchange.com/questions/686640/resolving-angular-components-in-2d-circular-rigid-body-collision-response// I still don't know how to derive this magic but I'm convinced it works // No idea if there's a sign error // It looks fine though var ca = { x: a.x - c.x, y: a.y - c.y }; var cb = { x: b.x - c.x, y: b.y - c.y }; var v = n.x * (a.vx - b.vx) + n.y * (a.vy - b.vy) - a.w * cr(ca, n) + b.w * cr(cb, n); var m = 1 / (1 / a.m + 1 / b.m + Math.pow(cr(ca, n), 2) / a.mi + Math.pow(cr(cb, n), 2) / b.mi); var j = 2 * m * v; const ca = { x: a.x - c.x, y: a.y - c.y }; const cb = { x: b.x - c.x, y: b.y - c.y }; const v = n.x * (a.vx - b.vx) + n.y * (a.vy - b.vy) - a.w * cr(ca, n) + b.w * cr(cb, n); const m = 1 / (1 / a.m + 1 / b.m + cr(ca, n) ** 2 / a.mi + cr(cb, n) ** 2 / b.mi); const j = 2 * m * v; a.vx += -n.x * j / a.m; a.vy += -n.y * j / a.m; a.w += cr(ca, n) * j / a.mi;
-
@@ -118,9 +111,8 @@ }// Collision of object a with wall at position k and direction d function wallCollide(a, k, d) { if ((!d && Math.abs(a.x - k) < a.r + rad) || (d && Math.abs(a.y - k) < a.r + rad)) { var c = { x: 0, y: 0, cnt: 0 }; for (var _i = 0, _a = a.p.map(function (x) { return rot(a, x); }); _i < _a.length; _i++) { var p = _a[_i]; let c = { x: 0, y: 0, cnt: 0 }; for (const p of a.p.map(x => rot(a, x))) { if ((!d && Math.abs(p.x - k) < rad) || (d && Math.abs(p.y - k) < rad)) { c.x += p.x; c.y += p.y;
-
@@ -130,7 +122,7 @@ }if (c.cnt > 0) { c.x /= c.cnt; c.y /= c.cnt; var b = { const b = { id: "", p: [], cm: { x: 0, y: 0 },
-
@@ -150,30 +142,26 @@ }} // Collision of object a with object b function objectsCollide(a, b) { if (ds(a, b) < Math.pow((a.r + b.r + 2 * rad), 2)) { if (ds(a, b) < (a.r + b.r + 2 * rad) ** 2) { // Objects are close var c = { x: 0, y: 0, cnt: 0 }; var n = { x: 0, y: 0 }; let c = { x: 0, y: 0, cnt: 0 }; let n = { x: 0, y: 0 }; // Slight performance optimization? // Only consider points close to other object var aa = []; var bb = []; for (var _i = 0, _a = a.p.map(function (x) { return rot(a, x); }); _i < _a.length; _i++) { var p = _a[_i]; if (ds(p, b) < Math.pow((a.r + b.r + 2 * rad), 2)) let aa = []; let bb = []; for (const p of a.p.map(x => rot(a, x))) { if (ds(p, b) < (a.r + b.r + 2 * rad) ** 2) aa.push(p); } for (var _b = 0, _c = b.p.map(function (x) { return rot(b, x); }); _b < _c.length; _b++) { var p = _c[_b]; if (ds(p, a) < Math.pow((a.r + b.r + 2 * rad), 2)) for (const p of b.p.map(x => rot(b, x))) { if (ds(p, a) < (a.r + b.r + 2 * rad) ** 2) bb.push(p); } for (var _d = 0, aa_1 = aa; _d < aa_1.length; _d++) { var p = aa_1[_d]; for (var _e = 0, bb_1 = bb; _e < bb_1.length; _e++) { var q = bb_1[_e]; var d = ds(p, q); if (d < Math.pow((2 * rad), 2)) { for (const p of aa) { for (const q of bb) { const d = ds(p, q); if (d < (2 * rad) ** 2) { // Collision! // These calculations are a bit sketchy but I guess they work? c.x += p.x + q.x;
-
@@ -188,7 +176,7 @@ if (c.cnt > 0) {c.x /= 2 * c.cnt; c.y /= 2 * c.cnt; // Normalize n var norm = Math.sqrt(Math.pow(n.x, 2) + Math.pow(n.y, 2)); const norm = Math.sqrt(n.x ** 2 + n.y ** 2); n.x /= norm; n.y /= norm; collide(a, b, c, n);
-
@@ -198,8 +186,7 @@ }// Move stuff, check collisions, and render function tick() { // Move each object one step for (var _i = 0, A_1 = A; _i < A_1.length; _i++) { var a = A_1[_i]; for (let a of A) { a.x += a.vx; a.y += a.vy; a.th += a.w;
-
@@ -223,16 +210,15 @@ if (Math.abs(a.w) > 0.00001)a.w -= 0.00001 * Math.sign(a.w); } // Check wall collisions for (var _a = 0, A_2 = A; _a < A_2.length; _a++) { var a = A_2[_a]; for (const a of A) { wallCollide(a, 0, false); wallCollide(a, window.innerWidth, false); wallCollide(a, 0, true); wallCollide(a, window.innerHeight, true); } // Check collisions between objects for (var i = 0; i < A.length; i++) { for (var j = i + 1; j < A.length; j++) { for (let i = 0; i < A.length; i++) { for (let j = i + 1; j < A.length; j++) { objectsCollide(A[i], A[j]); } }
-
@@ -240,9 +226,8 @@ // Render every 10mstickcnt++; if (tickcnt == 10) { tickcnt = 0; for (var _b = 0, A_3 = A; _b < A_3.length; _b++) { var a = A_3[_b]; var e = document.getElementById(a.id); for (let a of A) { let e = document.getElementById(a.id); if (e != null) { e.style.left = a.x - a.cm.x + "px"; e.style.top = a.y - a.cm.y + "px";
-
@@ -253,14 +238,13 @@ }} // Use click to update velocities function updatev(event) { for (var _i = 0, A_4 = A; _i < A_4.length; _i++) { var a = A_4[_i]; var d = Math.max(ds(a, { x: event.clientX, y: event.clientY }), 100); for (let a of A) { const d = Math.max(ds(a, { x: event.clientX, y: event.clientY }), 100); a.vx += 100 * (a.x - event.clientX) / d; a.vy += 100 * (a.y - event.clientY) / d; } // Display spreading out circles var circle = document.createElement("div"); let circle = document.createElement("div"); circle.style.width = circle.style.height = "10px"; circle.style.left = event.clientX - 5 + "px"; circle.style.top = event.clientY - 5 + "px";
-
@@ -271,6 +255,6 @@ setTimeout(function () {document.body.removeChild(circle); }, 1000); } var tickcnt = 0; let tickcnt = 0; setInterval(tick, 1); document.addEventListener("click", updatev);
-
-
-
@@ -1,6 +1,3 @@// See script.ts for original source code // Compile using tsc script.ts --lib esnext,dom --alwaysStrict // Inject SVG into DOM synchronously because we can't access the DOM of SVGs inside img tags document.querySelectorAll("svg").forEach(function (svg) { let req = new XMLHttpRequest()
-
-
tsconfig.json (new)
-
@@ -0,0 +1,7 @@{ "compilerOptions": { "strict": true, "target": "esnext" }, "files": ["script.ts"] }
-