Wandering and colliding blobs
This commit is contained in:
parent
52616dd10e
commit
18a21bb899
@ -1,39 +1,69 @@
|
|||||||
|
|
||||||
const WIDTH = 800;
|
const WIDTH = 400;
|
||||||
const HEIGHT = 800;
|
const HEIGHT = 400;
|
||||||
const NCRITTERS = 100;
|
const NCRITTERS = 10;
|
||||||
|
const CLOSE = 20;
|
||||||
|
const BOUNCE = 0.02;
|
||||||
|
|
||||||
const pointer = { x: 0, y: 0 };
|
const pointer = { x: 0, y: 0 };
|
||||||
|
|
||||||
const svg = document.getElementsByTagName("svg")[0];
|
const critters = [];
|
||||||
|
|
||||||
svg.addEventListener(
|
function dist(c1, c2) {
|
||||||
"pointermove",
|
const dx = c1.x - c2.x;
|
||||||
(e) => {
|
const dy = c1.y - c2.y;
|
||||||
pointer.x = e.clientX;
|
return Math.sqrt(dx * dx + dy * dy);
|
||||||
pointer.y = e.clientY;
|
}
|
||||||
},
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
class Critter {
|
class Critter {
|
||||||
constructor() {
|
constructor(i) {
|
||||||
|
this.i = i;
|
||||||
this.x = Math.random() * WIDTH;
|
this.x = Math.random() * WIDTH;
|
||||||
this.y = Math.random() * HEIGHT;
|
this.y = Math.random() * HEIGHT;
|
||||||
this.vx = Math.random() * 0.1 - 0.05;
|
this.vx = Math.random() * 0.1 - 0.05;
|
||||||
this.vy = Math.random() * 0.1 - 0.05;
|
this.vy = Math.random() * 0.1 - 0.05;
|
||||||
this.status = "go";
|
this.status = "go";
|
||||||
this.init();
|
}
|
||||||
this.update();
|
|
||||||
}
|
|
||||||
init() {
|
init() {
|
||||||
this.elt = document.createElement("circle");
|
const i0 = `c00${this.i}`;
|
||||||
this.elt.setAttribute("fill", "blue");
|
this.elt = document.getElementById(i0);
|
||||||
this.elt.setAttribute("r", 10);
|
console.log(`elt ${i0} ${this.elt}`);
|
||||||
this.elt.setAttribute("opacity", "50%");
|
}
|
||||||
svg.addChild(this.elt);
|
go_v(pos, vel) {
|
||||||
|
if( pos < 10 ) {
|
||||||
|
return vel + 0.01;
|
||||||
|
} else if ( pos > WIDTH - 10 ) {
|
||||||
|
return vel - 0.01;
|
||||||
|
} else {
|
||||||
|
return vel + Math.random() * 0.01 - 0.005;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
update() {
|
update() {
|
||||||
|
if( this.status === "collide" ) {
|
||||||
|
this.tick--;
|
||||||
|
if( this.tick === 0 ) {
|
||||||
|
this.status = "go";
|
||||||
|
this.elt.setAttribute("fill", "blue");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( this.status === "go" ) {
|
||||||
|
const collisions = critters.filter((c) => c.i != this.i && dist(c, this) < CLOSE);
|
||||||
|
if( collisions.length > 0 ) {
|
||||||
|
const hit = collisions[0];
|
||||||
|
this.status = "collide";
|
||||||
|
this.tick = 20;
|
||||||
|
this.elt.setAttribute("fill", "red");
|
||||||
|
this.vx = (this.x - collisions[0].x) * BOUNCE;
|
||||||
|
this.vy = (this.y - collisions[0].y) * BOUNCE;
|
||||||
|
hit.status = "collide";
|
||||||
|
hit.tick = 20;
|
||||||
|
hit.vx = -this.vx;
|
||||||
|
hit.vy = -this.vy;
|
||||||
|
} else {
|
||||||
|
this.vx = this.go_v(this.x, this.vx);
|
||||||
|
this.vy = this.go_v(this.y, this.vy);
|
||||||
|
}
|
||||||
|
}
|
||||||
this.x += this.vx;
|
this.x += this.vx;
|
||||||
this.y += this.vy;
|
this.y += this.vy;
|
||||||
this.elt.setAttribute("cx", this.x);
|
this.elt.setAttribute("cx", this.x);
|
||||||
@ -41,21 +71,32 @@ class Critter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const critters = [];
|
|
||||||
|
|
||||||
for( let i = 0; i++; i < NCRITTERS) {
|
|
||||||
critters.push(new Critter);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const svg = document.getElementsByTagName("svg")[0];
|
||||||
|
if (svg) { // Check if container exists
|
||||||
|
|
||||||
|
for( let i = 0; i < NCRITTERS; i++ ) {
|
||||||
|
const c = new Critter(i);
|
||||||
|
c.init(i);
|
||||||
|
c.update();
|
||||||
|
critters.push(c);
|
||||||
|
console.log(`added critter ${i}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log("Can't find svg element");
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
function animate() {
|
function animate() {
|
||||||
requestAnimationFrame(animate);
|
requestAnimationFrame(animate);
|
||||||
const rect = svg.getBoundingClientRect();
|
/* const rect = svg.getBoundingClientRect();
|
||||||
const x = pointer.x - rect.left;
|
const x = pointer.x - rect.left;
|
||||||
const y = pointer.y - rect.top;
|
const y = pointer.y - rect.top;
|
||||||
for( const c of critters ) {
|
*/ for( const c of critters ) {
|
||||||
c.update();
|
c.update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,11 +14,25 @@
|
|||||||
|
|
||||||
<p></p>
|
<p></p>
|
||||||
|
|
||||||
|
<div id="container">
|
||||||
|
<svg width="800" height="800" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle id="c000" r="10" cx="100" cy="100" fill="blue" fill-opacity="0.5"></circle>
|
||||||
|
<circle id="c001" r="10" cx="100" cy="100" fill="blue" fill-opacity="0.5"></circle>
|
||||||
|
<circle id="c002" r="10" cx="100" cy="100" fill="blue" fill-opacity="0.5"></circle>
|
||||||
|
<circle id="c003" r="10" cx="100" cy="100" fill="blue" fill-opacity="0.5"></circle>
|
||||||
|
<circle id="c004" r="10" cx="100" cy="100" fill="blue" fill-opacity="0.5"></circle>
|
||||||
|
<circle id="c005" r="10" cx="100" cy="100" fill="blue" fill-opacity="0.5"></circle>
|
||||||
|
<circle id="c006" r="10" cx="100" cy="100" fill="blue" fill-opacity="0.5"></circle>
|
||||||
|
<circle id="c007" r="10" cx="100" cy="100" fill="blue" fill-opacity="0.5"></circle>
|
||||||
|
<circle id="c008" r="10" cx="100" cy="100" fill="blue" fill-opacity="0.5"></circle>
|
||||||
|
<circle id="c009" r="10" cx="100" cy="100" fill="blue" fill-opacity="0.5"></circle>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
</div>
|
||||||
<p><a href="../">Back</a></p>
|
<p><a href="../">Back</a></p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<p><a href="https://git.tilde.town/bombinans/genuary2026/src/branch/main/06/genuary05.py">The Python script</p>
|
|
||||||
|
|
||||||
<script src="animate.js">
|
<script src="animate.js">
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user