summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--index.html12
-rw-r--r--script.js114
2 files changed, 66 insertions, 60 deletions
diff --git a/index.html b/index.html
index 822899d..eb6514b 100644
--- a/index.html
+++ b/index.html
@@ -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>
diff --git a/script.js b/script.js
index 188dbe3..d40711a 100644
--- a/script.js
+++ b/script.js
@@ -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
-}
-
-// 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")
+ svg.outerHTML = req.responseText
+})
-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 @@ document.querySelectorAll("svg").forEach(function(svg) {
}
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 @@ function collide(a, b, c, n) {
// 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 @@ function collide(a, b, c, n) {
a.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 @@ function wallCollide(a, k, d) {
}
}
+// 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 @@ function tick() {
// 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 @@ function updatev(event) {
circle.style.transform = "scale(500)"
circle.style.opacity = "0"
setTimeout(function () {
- document.body.removeChild(circle);
- }, 1000);
+ document.body.removeChild(circle)
+ }, 1000)
}
cnt = 0