Last active
September 8, 2022 03:11
-
-
Save JustinSDK/8cfad14db92981726d710d469a2f0e67 to your computer and use it in GitHub Desktop.
circle packing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const n_start = 200; | |
let circles = []; | |
function setup() { | |
createCanvas(640, 480); | |
noFill(); | |
strokeWeight(1.5); | |
stroke(5); | |
for (let i = 0; i < n_start; i++) { | |
circles[i] = new Circle(createVector(width / 2, height / 2), p5.Vector.random2D()); | |
} | |
} | |
function draw() { | |
background(255); | |
for (let c of circles) { | |
c.pack(circles); | |
circle(c.coordinate.x, c.coordinate.y, c.diameter); | |
} | |
} | |
class Circle { | |
constructor(coordinate, velocity, maxSpeed = 1.5, maxForce = 1.5, maxDiameter = 50) { | |
this.coordinate = coordinate; | |
this.velocity = velocity.limit(maxSpeed); | |
this.maxSpeed = maxSpeed; | |
this.maxForce = maxForce; | |
this.maxDiameter = maxDiameter; | |
this.diameter = 1; | |
} | |
applyForce(force) { | |
this.velocity.add(force); | |
} | |
separate(circles) { | |
let steer = createVector(0, 0); // 初始分離力 | |
// 計算期望速度 | |
for(let c of circles) { | |
let d = p5.Vector.dist(this.coordinate, c.coordinate); | |
// 交疊 | |
if(d > 0 && d < this.diameter / 2 + c.diameter / 2 + 2) { | |
let diff = p5.Vector | |
.sub(this.coordinate, c.coordinate) | |
// 跟距離平方成反比,越近影響越大 | |
.div(d * d); | |
steer.add(diff); // 累加 | |
} | |
} | |
// 如果速度不為 0 | |
if(steer.mag() > 0) { | |
steer.normalize(); // 只需要方向 | |
steer.mult(this.maxSpeed); // 拼命避開(用最大速度) | |
steer.sub(this.velocity); // 轉向力=期望速度-目前速度 | |
steer.limit(this.maxForce); // 限制力道 | |
} | |
return steer; | |
} | |
updateCoordinate() { | |
this.coordinate.add(this.velocity); | |
} | |
updateDiameter() { | |
this.diameter = | |
noise(this.coordinate.x * 0.01, this.coordinate.y * 0.01) * this.maxDiameter + 1; | |
} | |
pack(nodes) { | |
let sep = this.separate(nodes); | |
// 加總後套用至節點 | |
this.applyForce(sep); | |
// 更新座標 | |
this.updateCoordinate(); | |
this.updateDiameter(); | |
if(sep.mag() === 0) { | |
this.velocity.mult(0); | |
} | |
} | |
} | |
function mouseClicked() { | |
circles.push(new Circle(createVector(mouseX, mouseY), p5.Vector.random2D())); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment