Move SVG names to HTML, fix sign error in collide, move objectsCollide to its own function
This commit is contained in:
parent
d2ecf019b3
commit
64e928da30
12
index.html
12
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>
|
||||
|
|
114
script.js
114
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
|
||||
}
|
||||
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 @@ 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
|
||||
|
|
Loading…
Reference in a new issue