Changes
2 changed files (+66/-60)
-
-
@@ -1,11 +1,19 @@<!DOCTYPE html> <html> <head> <title>dumb physics engine</title> <meta name="description" content="Converts SVGs into a list of circles and use those circles for dumb collision checking"> <title>Dumb physics engine</title> <meta name="description" content="Converts SVGs into a set of circles and use those circles for dumb collision checking"> <link rel="stylesheet" href="style.css"> </head> <body> <!-- Draw 200x200 SVGs in Inkscape with the pencil tool and a stroke width of 20 Make sure the scale is set to 1 and that the id is set to a unique value Also, change the stroke to currentColor so we can style the color with CSS --> <svg id="hiragana-ni"></svg> <svg id="hiragana-small-ya"></svg> <svg id="hiragana-a"></svg> <script src="script.js"></script> </body> </html>
-
-
-
@@ -1,29 +1,22 @@// Inject SVG into DOM synchronously because we can't access the DOM of SVGs inside img tags function injectSVG(svg) { document.querySelectorAll("svg").forEach(function(svg) { let req = new XMLHttpRequest() req.open("GET", svg, false) req.open("GET", svg.id + ".svg", false) req.send() document.body.innerHTML += req.responseText } svg.outerHTML = req.responseText }) // Draw 200x200 SVGs in Inkscape with the pencil tool and a stroke width of 20 // Make sure the scale is set to 1 and that the id is set to a unique value // Also, change the stroke to currentColor so we can style the color with CSS injectSVG("hiragana-ni.svg") injectSVG("hiragana-small-ya.svg") injectSVG("hiragana-a.svg") let rad = 10 let size = 200 let A = [] let rad = 10 // Stroke width let size = 200 // SVG width and height let A = [] // Objects let cnt = 0 document.querySelectorAll("svg").forEach(function(svg) { // Move objects so they aren't overlapping svg.style.left = 1.5 * size * cnt++ + "px" svg.style.top = "50px" let a = { id: svg.id, // Unique ID p: [], // Collision circles of Array instances creates a new array populated with the results of calling a provided function on every element in the calling array. Try it Syntax js map(callbackFn) map(callbackFn, thisArg) Parameters callbackFn A function to execute for each element in the array. p: [], // Collision circles cm: svg.createSVGPoint(), // Center of mass vx: Math.random(), // x velocity vy: Math.random(), // y velocity
-
@@ -32,17 +25,17 @@ w: Math.random() / 100 // Angular velocity} svg.querySelectorAll("path").forEach(function(path) { // Get circles on path for collision checking for (let i = 0; i < path.getTotalLength(); i += rad) { for (let i = 0; i < path.getTotalLength(); i += 5) { const p = path.getPointAtLength(i) a.cm.x += p.x a.cm.y += p.y a.p.push(p) // Show circles for debugging /* let circle = document.createElementNS("http://www.w3.org/2000/svg", "circle"); circle.setAttribute("cx", p.x); circle.setAttribute("cy", p.y); circle.setAttribute("r", rad); circle.setAttribute("fill", "red"); /* let circle = document.createElementNS("http://www.w3.org/2000/svg", "circle") circle.setAttribute("cx", p.x) circle.setAttribute("cy", p.y) circle.setAttribute("r", rad) circle.setAttribute("fill", "red") svg.appendChild(circle) */ } })
-
@@ -87,6 +80,7 @@ // https://physics.stackexchange.com/questions/786641/collision-calculation-in-2d/786969#786969// 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 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)
-
@@ -97,8 +91,8 @@ a.vy += -n.y * j / a.ma.w += cr(ca, n) * j / a.mi b.vx += n.x * j / b.m b.vy += n.y * j / b.m b.w += cr(cb, n) * j / b.mi console.log('hi') b.w += -cr(cb, n) * j / b.mi console.log('boop') } // Collision of object a with wall at position k and direction d
-
@@ -123,6 +117,41 @@ }} } // Collision of object a with object b function objectsCollide(a, b) { if (ds(a, b) < size * size) { // Objects are close let c = {x: 0, y: 0, cnt: 0} let n = {x: 0, y: 0} for (const p of a.p.map(x => rot(a, x))) { // p is close to object b if (ds(p, b) < size * size) { for (const q of b.p.map(x => rot(b, x))) { const d = ds(p, q) if (d < 4 * rad * rad) { // Collision! // These calculations are a bit sketchy but I guess they work? c.x += p.x + q.x c.y += p.y + q.y c.cnt++ n.x += (p.x - q.x) / d n.y += (p.y - q.y) / d } } } } if (c.cnt > 0) { c.x /= 2 * c.cnt c.y /= 2 * c.cnt // Normalize n let norm = Math.sqrt(n.x ** 2 + n.y ** 2) n.x /= norm n.y /= norm collide(a, b, c, n) } } } function tick() { // Move each object one step for (let a of A) {
-
@@ -145,38 +174,7 @@// Check collisions between objects for (let i = 0; i < A.length; i++) { for (let j = i + 1; j < A.length; j++) { let a = A[i] let b = A[j] if (ds(a, b) < size * size) { // Objects are close let c = {x: 0, y: 0, cnt: 0} let n = {x: 0, y: 0} for (const p of a.p.map(x => rot(a, x))) { // p is close to object b if (ds(p, b) < size * size) { for (const q of b.p.map(x => rot(b, x))) { const d = ds(p, q) if (d < 4 * rad * rad) { // Collision! c.x += p.x + q.x c.y += p.y + q.y c.cnt++ n.x += (p.x - q.x) / d n.y += (p.y - q.y) / d } } } } if (c.cnt > 0) { c.x /= 2 * c.cnt c.y /= 2 * c.cnt let norm = Math.sqrt(n.x ** 2 + n.y ** 2) n.x /= norm n.y /= norm console.log(c.cnt, c, n) collide(a, b, c, n) } } objectsCollide(A[i], A[j]) } }
-
@@ -211,8 +209,8 @@ circle.offsetWidthcircle.style.transform = "scale(500)" circle.style.opacity = "0" setTimeout(function () { document.body.removeChild(circle); }, 1000); document.body.removeChild(circle) }, 1000) } cnt = 0
-