top of page
Search
cedarcantab

Squishy Circle



let palette = ["#0a0a0a", "#f7f3f2", "#0077e1", "#f5d216", "#fc3503"],

N_PARTICLES_X,

N_PARTICLES_Y,

particles = [],

springs = [],

grid,

WID = 400,

HEI = 400,

PAD = 50;

function setup() {

createCanvas(WID, HEI),

(grid = new Grid(WID, HEI, 22)),

(blob = new Blob(

{ x: WID / 4 + 20, y: HEI / 4 + 20 },

120,

39

)).makeParticlesAndSprings(),

(blob2 = new Blob(

{ x: (WID / 4) 3, y: (HEI / 4) 3 },

80,

33

)).makeParticlesAndSprings();

}

function draw() {

background(0), blob.display(), blob.run(), blob2.display(), blob2.run();

}

class Blob {

constructor(s, t, i) {

(this.startPos = s),

(this.radius = t),

(this.detail = i),

(this.col = random(palette)),

(this.particles = []),

(this.springs = []);

}

makeParticlesAndSprings() {

let s = [];

for (let t = 0; t < TAU; t += TAU / this.detail) {

let i = this.startPos.x + this.radius * cos(t),

e = this.startPos.y + this.radius * sin(t),

o = new Particle(new createVector(i, e));

s.push(o);

}

for (let l = 0; l < s.length; l++) {

let r = s[l],

h = s[(l + 1) % s.length];

this.springs.push(

new Spring(r, h, dist(r.pos.x, r.pos.y, h.pos.x, h.pos.y), 0.25)

);

}

for (let p = 0; p < s.length; p++) {

let a = s[p],

c = s[(p + 2) % s.length];

this.springs.push(

new Spring(a, c, dist(a.pos.x, a.pos.y, c.pos.x, c.pos.y), 0.25)

);

}

for (let d of s) this.particles.push(d), grid.addParticle(d);

let n = [];

this.detail = int(this.detail / 2);

for (let u = 0; u < TAU; u += TAU / this.detail) {

let g = this.startPos.x + (this.radius / 2) * cos(u),

y = this.startPos.y + (this.radius / 2) * sin(u),

f = new Particle(new createVector(g, y));

n.push(f);

}

for (let $ = 0; $ < n.length; $++) {

let x = n[$],

m = n[($ + 1) % n.length];

this.springs.push(

new Spring(x, m, dist(x.pos.x, x.pos.y, m.pos.x, m.pos.y), 0.25)

);

}

for (let v = 0; v < n.length; v++) {

let S = n[v],

P = n[(v + 2) % n.length];

this.springs.push(

new Spring(S, P, dist(S.pos.x, S.pos.y, P.pos.x, P.pos.y), 0.25)

);

}

for (let of n) this.particles.push(), grid.addParticle(_);

for (let w = 0; w < n.length; w++) {

let V = s[int(2 * w)],

F = n[w];

this.springs.push(

new Spring(V, F, dist(V.pos.x, V.pos.y, F.pos.x, F.pos.y), 0.25)

),

(V = s[(int(2 * w) + 1) % s.length]),

(F = n[w]),

this.springs.push(

new Spring(V, F, dist(V.pos.x, V.pos.y, F.pos.x, F.pos.y), 0.25)

),

(V = s[int(2 * w) % s.length]),

(F = n[(w + 1) % n.length]),

this.springs.push(

new Spring(V, F, dist(V.pos.x, V.pos.y, F.pos.x, F.pos.y), 0.25)

);

}

particles.push(...this.particles);

}

run() {

for (let s of this.springs) s.update();

for (let t of this.particles) {

let i = grid.getNeighbors(t);

t.checkCollision(i), t.checkEdges(), t.updateState(), t.limitVelocities();

}

for (let e of this.particles) grid.removeParticle(e), grid.addParticle(e);

}

display() {

for (let s of this.particles) s.display();

for (let t of this.springs) t.display();

}

}

class Particle {

constructor(s) {

(this.pos = s),

(this.velocity = createVector(random(-1, 1), random(-1, 1))),

(this.acceleration = createVector(0, 0)),

(this.mass = 1.25),

(this.radius = 5 * this.mass),

(this.maxSpeed = 7),

(this.dragging = !1);

}

mousePressed() {

dist(mouseX, mouseY, this.pos.x, this.pos.y) < this.radius &&

(this.dragging = !0);

}

mouseReleased() {

this.dragging = !1;

}

updateState(s) {

this.dragging

? ((this.velocity = p5.Vector.sub(

createVector(mouseX, mouseY),

this.pos

)),

this.pos.add(this.velocity))

: (this.addForce(this.acceleration),

this.limitVelocities(),

this.pos.add(this.velocity));

}

checkEdges() {

this.pos.x - this.radius < 0

? ((this.pos.x = this.radius),

(this.velocity.x *= -0.25),

this.addForce(createVector(1, 0)))

: this.pos.x + this.radius > width &&

((this.pos.x = width - this.radius),

(this.velocity.x *= -0.25),

this.addForce(createVector(-1, 0))),

this.pos.y - this.radius < 0

? ((this.pos.y = this.radius),

(this.velocity.y *= -0.25),

this.addForce(createVector(0, 1)))

: this.pos.y + this.radius > height &&

((this.pos.y = height - this.radius),

(this.velocity.y *= -0.25),

this.addForce(createVector(0, -1)));

}

checkCollision(s) {

for (let t of (console.log(s.length), s))

if (this != t) {

let i = this.pos.dist(t.pos),

e = this.radius + t.radius;

if (i <= e) {

let o = p5.Vector.sub(t.pos, this.pos).normalize(),

l = p5.Vector.sub(t.velocity, this.velocity),

r = p5.Vector.mult(o, (2 * p5.Vector.dot(l, o)) / 2),

h = p5.Vector.mult(o, e - i);

this.addForce(p5.Vector.div(r, this.mass)),

t.addForce(p5.Vector.div(r, -t.mass)),

this.addForce(p5.Vector.div(h, -this.mass)),

t.addForce(p5.Vector.div(h, t.mass));

}

}

}

addForce(s) {

this.velocity.add(s.div(this.mass));

}

limitVelocities() {

var s = sqrt(

this.velocity.x this.velocity.x + this.velocity.y this.velocity.y

);

s > this.maxSpeed && this.velocity.mult(this.maxSpeed / s);

}

display() {

stroke(255), fill(255), ellipse(this.pos.x, this.pos.y, 2 * this.radius);

}

displayDirection() {

push(),

strokeWeight(3),

stroke(255, 0, 0),

line(

this.pos.x,

this.pos.y,

this.pos.x + 2 * this.velocity.x,

this.pos.y + 2 * this.velocity.y

),

stroke(0, 0, 255),

line(

this.pos.x,

this.pos.y,

this.pos.x + 2 * this.acceleration.x,

this.pos.y + 2 * this.acceleration.y

),

pop();

}

}

function mousePressed() {

for (let s = 0; s < particles.length; s++) particles[s].mousePressed();

}

function mouseReleased() {

for (let s = 0; s < particles.length; s++) particles[s].mouseReleased();

}

class Grid {

constructor(s, t, i) {

(this.cellSize = i),

(this.numCols = Math.ceil(s / i)),

(this.numRows = Math.ceil(t / i)),

(this.cells = []);

for (let e = 0; e < this.numCols; e++) {

this.cells[e] = [];

for (let o = 0; o < this.numRows; o++) this.cells[e][o] = [];

}

}

addParticle(s) {

let t = Math.floor(s.pos.x / this.cellSize),

i = Math.floor(s.pos.y / this.cellSize);

this.cells[t][i].push(s), (s.gridCell = { col: t, row: i });

}

removeParticle(s) {

let { col: t, row: i } = s.gridCell,

e = this.cells[t][i],

o = e.indexOf(s);

e.splice(o, 1);

}

getNeighbors(s) {

let t = [

floor((s.pos.x - s.radius) / this.cellSize),

floor((s.pos.y - s.radius) / this.cellSize)

],

i = [

floor((s.pos.x + s.radius) / this.cellSize),

floor((s.pos.y + s.radius) / this.cellSize)

],

e = [];

for (let o = t[0]; o <= i[0]; o++)

for (let l = t[1]; l <= i[1]; l++) {

if (o < 0 || l < 0 || o >= this.numCols || l >= this.numRows) continue;

let r = this.cells[o][l];

for (let h of r) h != s && e.push(h);

}

return e;

}

}

class Spring {

constructor(s, t, i, e) {

(this.particleA = s),

(this.particleB = t),

(this.restLength = i),

(this.stiffness = e),

(this.damping = 0.05);

}

update() {

let s = p5.Vector.sub(this.particleA.pos, this.particleB.pos),

t = s.mag();

var i = t - this.restLength,

e = this.stiffness * i;

let o = p5.Vector.mult(p5.Vector.div(s, t), e);

this.particleA.addForce(p5.Vector.mult(o, -1)), this.particleB.addForce(o);

let l = p5.Vector.mult(

p5.Vector.sub(this.particleA.velocity, this.particleB.velocity),

this.damping

);

this.particleA.addForce(p5.Vector.mult(l, -1)), this.particleB.addForce(l);

}

display() {

stroke(255),

line(

this.particleA.pos.x,

this.particleA.pos.y,

this.particleB.pos.x,

this.particleB.pos.y

);

}

}


2 views0 comments

Recent Posts

See All

p2 naive broadphase

var Broadphase = require('../collision/Broadphase'); module.exports = NaiveBroadphase; /** * Naive broadphase implementation. Does N^2...

sopiro motor constranit

import { Matrix2, Vector2 } from "./math.js"; import { RigidBody } from "./rigidbody.js"; import { Settings } from "./settings.js";...

Comentários


記事: Blog2_Post
bottom of page