
์ด๋ฒ์๋ ํํฐํด(Particle)๊ณผ ์์ด์ ํธ(Agent)๋ผ๋ ๋จ์ด๊ฐ ๋ฑ์ฅํฉ๋๋ค. ์ ๋๋ฉ์ด์ ์ ๋ณด๋ฉด ์ผํ ๋น์ทํด๋ณด์ด๋ ํ๋ ์์์ ๋ชฉํ๊ฐ ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ๊ตฌ๋ถํด์ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
ํํฐํด์ ๋จ์ํ ์์น์ ์๋๋ง ๊ฐ์ง ๋ฌผ๋ฆฌ์ ์ธ ์ ์ ๋๋ค. ๊ณต์ ๋์ง๋ฉด ๋ฌผ๋ฆฌ๋ฒ์น์ ์ํด ํฌ๋ฌผ์ ์ ๊ทธ๋ฆฌ๋ฉฐ ๋จ์ด์ง๋๋ฐ ๊ทธ๊ฒ์ ์๊ฐํํ ๊ฒ์ด ํํฐํด์ ๋๋ค. ์ค๋ ฅ์ ๊ฑฐ์ฌ๋ฌ์ ์ฌ๋ผ๊ฑฐ๋, ํ ์ ์์ ํผ์ ธ๋๊ฐ๋ ์ ํด์ง ๋ฒ์น์ ์ํด์ ๋ฐ์ํ๊ณ ์์ง์ด๊ณ ์ฌ๋ฆฌ์ง๋ ์์ ๋ฌผ์ฒด๋ค์ ๋๋ค.
๋ฐ๋ฉด์ ์์ด์ ํธ๋ ์ด ํํฐํด์ ์ฑ๊ฒฉ์ ๊ท์น๊ณผ ํ๋ ์์์ ๋ํด ์ง๋ฅ์ ์ผ๋ก ์์ง์ด๊ฒ ํ ๊ฒ์ ๋๋ค. ๋์ง ๊ณต์ด ์ฅ์ ๋ฌผ์ ํผํ๊ณ ์์ง์ด๋ ๋ชฉํ๋ฌผ์ ๋ฐ๋ผ ๋ ์๊ฐ๋ ํ๋์ ๋ณด์ด๋๋ก ํ ๊ฒ์ด ์์ด์ ํธ์ ๋๋ค. ์์ด์ ํธ๋ค์ ์ํธ์์ฉํ๋ฉด์ ๋ณต์กํ ์์คํ ์ ์ด๋ฃฐ ์ ์์ต๋๋ค. ์ด๋ ์ ์ฉ๋๋ ํน์ง์ ์์จ์ฑ(Autonomy), ๋ฐ์์ฑ(Reactivity), ๊ทธ๋ฆฌ๊ณ ๋ชฉํ ์งํฅ์ฑ(Goal-Oriented)์ ๋๋ค. ์ํธ์์ฉ์ ์ฐฝ๋ฒ์ ํ๋(emergent behavior)์ ๋ง๋ค์ด๋ด๊ณ ๋ง์น ์ด์์๋ ์ ๊ธฐ์ฒด์ ํจํด์ฒ๋ผ ๋ณด์ด๊ฒ๋ ํฉ๋๋ค.
์ด๋ฒ ์ฃผ์ฐจ๋ ๋ค์๊ณผ ๊ฐ์ ์์ฃผ์ ๋ก ๊ตฌ์ฑ๋ฉ๋๋ค.
- ๊ธฐ๋ณธ ํํฐํด ์๋ฆฌ (๋์์๋ ์์ฑ)
- Attaction๊ณผ Repulsion
- Seeking
- Flocking / Boids
- Flow Field
- Path Following & Avoidance
- Propagation & Diffusion
- Spring & Constraints
- Self-Organazing Map (SOM)
- Lifespan & Emitter

// ์ ์ญ ๋ฐฐ์ด 'particles' ์ ์ธ: ์์ฑ๋ ๋ชจ๋ ์
์ ๊ฐ์ฒด๋ค์ ์ ์ฅํ ๊ณต๊ฐ์
๋๋ค.
let particles = [];
// setup() ํจ์: p5.js ํ๋ก๊ทธ๋จ์ด ์์๋ ๋ ๋จ ํ ๋ฒ ์คํ๋ฉ๋๋ค. ์ด๊ธฐ ํ๊ฒฝ ์ค์ ์ ๋ด๋นํฉ๋๋ค.
function setup() {
// createCanvas(width, height): ์บ๋ฒ์ค(๊ทธ๋ฆผ์ ๊ทธ๋ฆด ์์ญ)์ ํฌ๊ธฐ๋ฅผ 800x400 ํฝ์
๋ก ์ค์ ํฉ๋๋ค.
createCanvas(800, 400);
}
// draw() ํจ์: ํ๋ก๊ทธ๋จ ์คํ ์ค ์ง์์ ์ผ๋ก, ์ด๋น ์ฝ 60ํ๋ ์ ์๋๋ก ๋ฐ๋ณต ์คํ๋ฉ๋๋ค. ์ ๋๋ฉ์ด์
์ ํต์ฌ ๋ฃจํ์
๋๋ค.
function draw() {
// background(r, g, b): ๋งค ํ๋ ์๋ง๋ค ๋ฐฐ๊ฒฝ์ ์ด๋์ด ํ์(25)์ผ๋ก ์น ํฉ๋๋ค.
// ์ด๋ฅผ ํตํด ์ด์ ํ๋ ์์ ์
์๋ค์ด ์ง์์ง๊ณ ์์ง์ด๋ ํจ๊ณผ๊ฐ ๋ง๋ค์ด์ง๋๋ค.
background(25);
// ์๋ก์ด ์
์ ์์ฑ
// particles ๋ฐฐ์ด์ ์๋ก์ด Particle ๊ฐ์ฒด๋ฅผ ์ถ๊ฐํฉ๋๋ค.
// width / 2๋ ์บ๋ฒ์ค์ ๊ฐ๋ก ์ค์์ ์๋ฏธํ๋ฉฐ, 100์ ์๋จ์์ 100ํฝ์
์๋ ์์น๋ฅผ ์๋ฏธํฉ๋๋ค.
particles.push(new Particle(width / 2, 100));
// ์
์ ์
๋ฐ์ดํธ ๋ฐ ๋ ๋๋ง
// for ๋ฃจํ๋ฅผ ์ฌ์ฉํ์ฌ particles ๋ฐฐ์ด์ ๋ชจ๋ ์
์๋ค์ ์ํํฉ๋๋ค.
// ๋ฐฐ์ด ๋์์๋ถํฐ ์์ํ์ฌ ์ญ์์ผ๋ก ์ํํ๋ ์ด์ ๋,
// ๋ฃจํ ๋์ค์ ์
์๋ฅผ ๋ฐฐ์ด์์ ์ ๊ฑฐ(splice)ํ ๋ ์ธ๋ฑ์ค ์ค๋ฅ๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํจ์
๋๋ค.
for (let i = particles.length - 1; i >= 0; i--) {
// ํ์ฌ ์ํ ์ค์ธ ์
์ ๊ฐ์ฒด๋ฅผ p ๋ณ์์ ํ ๋นํฉ๋๋ค.
let p = particles[i];
// p.update(): ์
์์ ์์น, ์๋, ์๋ช
์ ์
๋ฐ์ดํธํฉ๋๋ค.
p.update();
// p.show(): ์บ๋ฒ์ค์ ์
์๋ฅผ ๊ทธ๋ฆฝ๋๋ค.
p.show();
// p.isDead(): ์
์์ ์๋ช
์ด ๋คํ๋์ง ํ์ธํฉ๋๋ค.
if (p.isDead()) {
// ์
์๊ฐ ์ฃฝ์๋ค๋ฉด, particles ๋ฐฐ์ด์์ ํด๋น ์
์๋ฅผ ์ ๊ฑฐํฉ๋๋ค. (i๋ฒ์งธ ์ธ๋ฑ์ค๋ถํฐ 1๊ฐ)
particles.splice(i, 1);
}
}
}
// Particle ํด๋์ค: ๊ฐ๋ณ ์
์์ ์์ฑ๊ณผ ๋์์ ์ ์ํ๋ ์ค๊ณ๋์
๋๋ค.
class Particle {
// constructor(x, y): ์๋ก์ด Particle ๊ฐ์ฒด๊ฐ ์์ฑ๋ ๋ ์ด๊ธฐ ์์ฑ์ ์ค์ ํฉ๋๋ค.
// x, y๋ ์
์๊ฐ ์ฒ์ ์์ฑ๋ ์ด๊ธฐ ์์น์
๋๋ค.
constructor(x, y) {
// this.pos: p5.Vector ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ ์
์์ ์์น(x, y)๋ฅผ ์ ์ฅํฉ๋๋ค.
this.pos = createVector(x, y);
// this.vel: p5.Vector ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ ์
์์ ์๋(velocity)๋ฅผ ์ ์ฅํฉ๋๋ค.
// p5.Vector.random2D()๋ ๋ฌด์์ ๋ฐฉํฅ์ ๋จ์ ๋ฒกํฐ๋ฅผ ์์ฑํ๊ณ ,
// mult(random(1, 3))๋ฅผ ํตํด ์๋์ ํฌ๊ธฐ๋ฅผ 1์์ 3 ์ฌ์ด์ ๋ฌด์์ ๊ฐ์ผ๋ก ์ค์ ํ์ฌ ์ด๊ธฐ ํ์ฐ ํจ๊ณผ๋ฅผ ์ค๋๋ค.
this.vel = p5.Vector.random2D().mult(random(1, 3));
// this.acc: p5.Vector ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ ์
์์ ๊ฐ์๋(acceleration)๋ฅผ ์ ์ฅํฉ๋๋ค.
// (0, 0.05)๋ y์ถ ๋ฐฉํฅ(์๋์ชฝ)์ผ๋ก ์ผ์ ํ ์ค๋ ฅ ๊ฐ์๋๋ฅผ ์๋ฏธํฉ๋๋ค.
this.acc = createVector(0, 0.05);
// this.lifetime: ์
์์ ๋จ์ ์๋ช
์ 255(์ต๋ ๋ถํฌ๋ช
๋ ๊ฐ)๋ก ์ด๊ธฐ ์ค์ ํฉ๋๋ค.
this.lifetime = 255;
}
// update() ๋ฉ์๋: ๋งค ํ๋ ์๋ง๋ค ์
์์ ๋ฌผ๋ฆฌ์ ์ธ ์ํ๋ฅผ ๊ฐฑ์ ํฉ๋๋ค.
update() {
// ์๋์ ๊ฐ์๋๋ฅผ ๋ํฉ๋๋ค (์ค๋ ฅ์ ์ํฅ์ผ๋ก ์๋๊ฐ ์ ์ ๋นจ๋ผ์ง).
this.vel.add(this.acc);
// ์์น์ ํ์ฌ ์๋๋ฅผ ๋ํฉ๋๋ค (์ค์ ์
์ ์ด๋).
this.pos.add(this.vel);
// ์๋ช
์ 2์ฉ ๊ฐ์์ํต๋๋ค (์ ์ ํฌ๋ช
ํด์ง๊ณ ์ฌ๋ผ์ง).
this.lifetime -= 2;
}
// show() ๋ฉ์๋: ํ์ฌ ์์น์ ์๋ช
(ํฌ๋ช
๋)์ ๊ธฐ๋ฐ์ผ๋ก ์
์๋ฅผ ํ๋ฉด์ ๊ทธ๋ฆฝ๋๋ค.
show() {
// noStroke(): ์
์ ๋ํ์ ํ
๋๋ฆฌ ์ ์ ๊ทธ๋ฆฌ์ง ์๋๋ก ์ค์ ํฉ๋๋ค.
noStroke();
// fill(r, g, b, alpha): ์
์์ ์ฑ์ฐ๊ธฐ ์์์ ์ค์ ํฉ๋๋ค.
// ๋
ธ๋์(210, 180, 30)์ ํ์ฌ ์๋ช
(this.lifetime)์ ํฌ๋ช
๋(alpha)๋ก ์ฌ์ฉํ์ฌ
// ์๊ฐ์ด ์ง๋ ์๋ก ์
์๊ฐ ํ๋ฆฟํด์ง๋๋ก ๋ง๋ญ๋๋ค.
fill(210, 180, 30, this.lifetime);
// ellipse(x, y, w, h): ํ์ฌ ์์น(this.pos.x, this.pos.y)์ ์ง๋ฆ 8ํฝ์
์ ์์ ๊ทธ๋ฆฝ๋๋ค.
ellipse(this.pos.x, this.pos.y, 8);
}
// isDead() ๋ฉ์๋: ์
์๊ฐ ์ ๊ฑฐ๋์ด์ผ ํ ์์ ์ ํ๋จํฉ๋๋ค.
isDead() {
// ์๋ช
์ด 0๋ณด๋ค ์์์ง๋ฉด true๋ฅผ ๋ฐํํ์ฌ ์
์๊ฐ '์ฃฝ์์'์ ์๋ฆฝ๋๋ค.
return this.lifetime < 0;
}
}
๐ ํต์ฌ ๊ฐ๋

๊ฐ๋ : ๋ฌผ๋ฆฌ ๋ฒ์น์ ์๋ฎฌ๋ ์ด์ ํ๋ ๋ฐ ์ค์ ์ ๋ก๋๋ค. ๋ ๋ฌผ์ฒด ์ฌ์ด์ ์์ฉํ๋ ํ(Force)์ ํฌ๊ธฐ๋ฅผ ๊ฑฐ๋ฆฌ์ ์ ๊ณฑ์ ๋ฐ๋น๋กํ๊ฒ ๊ณ์ฐํฉ๋๋ค (๋ง์ ์ธ๋ ฅ).
๋ก์ง์ ํต์ฌ:๋ชฉํ ์ง์ ๊น์ง์ ๊ฑฐ๋ฆฌ ์ ๋ฐฉํฅ ์ ๊ณ์ฐํฉ๋๋ค.ํ์ ํฌ๊ธฐ ๋ฅผ ๊ณ์ฐํฉ๋๋ค. (์ผ๋ฐ์ ์ผ๋ก ์ด์ง๋ง, ๋จ์ํํ์ฌ ๋ฑ์ผ๋ก ์ฌ์ฉ๋๊ธฐ๋ ํฉ๋๋ค.)์ด ํ์ ๊ฐ์๋์ ์ง์ ์ ์ฉํฉ๋๋ค.
๊ฒฐ๊ณผ: ๋ชฉํ ์ง์ ์ ๋๋ฌํ ๋ ์๋๋ฅผ ์กฐ์ ํ๋ ๋ฉ์ปค๋์ฆ(์กฐํฅ๋ ฅ)์ด ์์ผ๋ฉด, ๊ด์ฑ ๋๋ฌธ์ ๋ชฉํ ์ง์ ์ ํต๊ณผํ์ฌ ํ๊ฒจ ๋๊ฐ๊ฑฐ๋ ๋ชฉํ ์ฃผ๋ณ์ ์ง๋ํ๋ฉฐ ๋งด๋๋ (๊ถค๋๋ฅผ ๋๋) ๊ฒฝํฅ์ด ๊ฐํฉ๋๋ค.
let particles = [];
let attractMode = true; // true๋ฉด ๋๋ฆผ, false๋ฉด ๋ฐ์ด๋
function setup() {
createCanvas(800, 400);
for (let i = 0; i < 2000; i++) {
particles.push(new Particle(random(width), random(height)));
}
}
function draw() {
background(2, 10);
fill(255);
noStroke();
text(attractMode ? "Attraction Mode" : "Repulsion Mode", 10, 20);
for (let p of particles) {
p.behaviors();
p.update();
p.show();
}
}
function mousePressed() {
attractMode = !attractMode;
}
class Particle {
constructor(x, y) {
this.pos = createVector(x, y);
this.vel = p5.Vector.random2D();
this.acc = createVector();
}
behaviors() {
let mouse = createVector(mouseX, mouseY);
let dir = p5.Vector.sub(mouse, this.pos);
let d = dir.mag();
d = constrain(d, 10, 30);
dir.normalize();
let strength = attractMode ? 5.0 / d : -5.0 / d;
dir.mult(strength);
this.acc = dir;
}
update() {
this.vel.add(this.acc);
this.pos.add(this.vel);
this.vel.limit(5);
}
show() {
stroke(255);
strokeWeight(4);
point(this.pos.x, this.pos.y);
}
}
๐ ํต์ฌ ๊ฐ๋

๊ฐ๋ : Steering Behavior (์กฐํฅ ํ๋)์ ์ผ์ข ์ ๋๋ค. ์์ด์ ํธ(ํํฐํด)๊ฐ ๋ชฉํ ์ง์ (Target)์ผ๋ก ๊ฐ์ฅ ํจ์จ์ ์ธ ๊ฒฝ๋ก๋ฅผ ์ฐพ์๊ฐ๋๋ก ๋ฐฉํฅ์ ์กฐ์ ํ๋ ๋ฐ ์ค์ ์ ๋ก๋๋ค.
๋ก์ง์ ํต์ฌ:
// sketch.js
let NUM_AGENTS = 80;
let agents = [];
function setup() {
createCanvas(800, 400);
background(25); // ์บ๋ฒ์ค๋ฅผ ๊นจ๋ํ๊ฒ ์์
for (let i = 0; i < NUM_AGENTS; i++) {
let start = createVector(
width / 2 + random(-20, 20),
height / 2 + random(-20, 20)
);
agents.push(new Agent(start));
}
}
function draw() {
// ๋ฐฐ๊ฒฝ: ์ด๋์ด ํ์ (25) ๋ฐ ๊ผฌ๋ฆฌ ํจ๊ณผ
fill(0, 5);
noStroke();
rect(0, 0, width, height);
let target = createVector(mouseX, mouseY);
for (let agent of agents) {
// --- 1. ๋ ๊ฐ์ง ํ ๊ณ์ฐ ---
// 1-1. ๋ถ๋ฆฌ(Separation) ํ ๊ณ์ฐ: ๋ค๋ฅธ ์์ด์ ํธ๋ก๋ถํฐ ๋ฉ์ด์ง๋ ค๋ ํ
let separation = agent.separate(agents);
// 1-2. ์ถ์ (Seeking) ํ ๊ณ์ฐ: ๋ชฉํ ์ง์ (๋ง์ฐ์ค)์ ํฅํด ๊ฐ๋ ค๋ ํ
let seeking = agent.seek(target);
// --- 2. ํ์ ๊ฐ์ค์น๋ฅผ ๋ถ์ฌํ๊ณ ์ ์ฉ ---
// ๋ถ๋ฆฌ ํ์ ๋ ๋์ ๊ฐ์ค์น(1.2)๋ฅผ ๋ถ์ฌํ์ฌ ๊ฒน์น๋ ๊ฒ์ ๋ฐฉ์ง
separation.mult(1.2);
// ์ถ์ ํ์๋ ํ์ค ๊ฐ์ค์น(1.0) ๋ถ์ฌ
seeking.mult(1.0);
// ๊ณ์ฐ๋ ํ์ ๋ชจ๋ ์ ์ฉ
agent.applyForce(separation);
agent.applyForce(seeking);
// --- 3. ์
๋ฐ์ดํธ ๋ฐ ๋ ๋๋ง ---
agent.update();
agent.checkEdges();
agent.display();
}
}
// ---------------------------------------------------------------------
// Agent ํด๋์ค ์ ์ (seperation ๋ก์ง ๋ฐ seeking ๋ก์ง )
// ---------------------------------------------------------------------
class Agent {
constructor(l) {
this.position = l;
this.velocity = p5.Vector.random2D();
this.acceleration = createVector(0, 0);
this.maxSpeed = 2.0;
this.maxForce = 0.2;
this.radius = 2;
// ๊ฐ์ฒด ์์: ์ฐํธ์(Coral, RGB: 255, 127, 80)
this.agentColor = color(255, 127, 80);
}
applyForce(force) {
this.acceleration.add(force);
}
// Seeking ๋ฉ์๋๊ฐ ํ์ ๋ฐ๋ก ์ ์ฉํ์ง ์๊ณ Steering Force ๋ฒกํฐ๋ฅผ ๋ฐํํ๋๋ก ์์
seek(target) {
let desired = p5.Vector.sub(target, this.position);
desired.normalize();
desired.mult(this.maxSpeed);
let steer = p5.Vector.sub(desired, this.velocity);
steer.limit(this.maxForce);
return steer; // ํ์ ๋ฐํ
}
// --- ์๋ก ์ถ๊ฐ๋ Separation (๋ถ๋ฆฌ) ํ๋ ๊ตฌํ ---
separate(agents) {
let desiredSeparation = this.radius * 2 + 10; // ๋๋ฌด ๊ฐ๊น์์ง๋ฉด ๋ถ๋ฆฌ ์์ํ ๊ฑฐ๋ฆฌ
let sum = createVector(0, 0);
let count = 0;
for (let other of agents) {
let d = p5.Vector.dist(this.position, other.position);
// ๋ค๋ฅธ ์์ด์ ํธ์ด๊ณ , ๋๋ฌด ๊ฐ๊น์ด ์๋ค๋ฉด
if (d > 0 && d < desiredSeparation) {
// ์ด์์ผ๋ก๋ถํฐ ๋ฉ์ด์ง๋ ๋ฐฉํฅ ๋ฒกํฐ ๊ณ์ฐ
let diff = p5.Vector.sub(this.position, other.position);
diff.normalize();
// ๊ฑฐ๋ฆฌ๊ฐ ๊ฐ๊น์ธ์๋ก ๊ฐํ ํ์ ๋ถ์ฌ (๊ฑฐ๋ฆฌ์ ์ ๊ณฑ์ด ์๋, ๋จ์ ๊ฑฐ๋ฆฌ๋ก ๋๋)
diff.div(d);
sum.add(diff);
count++;
}
}
if (count > 0) {
sum.div(count); // ํ๊ท ๋ถ๋ฆฌ ๋ฐฉํฅ ๊ณ์ฐ
// Steering Behavior ๋ก์ง์ ์ ์ฉํ์ฌ ์ต์ข
๋ถ๋ฆฌ ํ ๊ณ์ฐ
sum.normalize();
sum.mult(this.maxSpeed);
let steer = p5.Vector.sub(sum, this.velocity);
steer.limit(this.maxForce);
return steer;
}
return createVector(0, 0);
}
// -------------------------------------------------------
update() {
this.velocity.add(this.acceleration);
this.velocity.limit(this.maxSpeed);
this.position.add(this.velocity);
this.acceleration.mult(0);
}
checkEdges() {
if (this.position.x > width) this.position.x = 0;
else if (this.position.x < 0) this.position.x = width;
if (this.position.y > height) this.position.y = 0;
else if (this.position.y < 0) this.position.y = height;
}
display() {
stroke(this.agentColor);
fill(this.agentColor, 200);
ellipse(this.position.x, this.position.y, this.radius * 2, this.radius * 2);
}
}

// Separation (๋ถ๋ฆฌ) : ๋๋ฌด ๊ฐ๊น์ฐ๋ฉด ๋ฉ์ด์ง๊ฒ
// Alignment (์ ๋ ฌ) : ์ฃผ๋ณ์ ํ๊ท ์๋์ ๋น์ทํ๊ฒ
// Cohesion (์์ง) : ์ฃผ๋ณ ๊ฐ์ฒด์ ์ค์ฌ์ผ๋ก ์ด๋
let flock = [];
function setup() {
createCanvas(800, 400);
for (let i = 0; i < 250; i++) {
flock.push(new Boid());
}
}
function draw() {
background(25);
for (let boid of flock) {
boid.flock(flock);
boid.update();
boid.edges();
boid.show();
}
}
class Boid {
constructor() {
this.pos = createVector(random(width), random(height));
this.vel = p5.Vector.random2D();
this.vel.setMag(random(2, 4));
this.acc = createVector();
this.maxForce = 0.1;
this.maxSpeed = 2;
}
edges() {
if (this.pos.x > width) this.pos.x = 0;
if (this.pos.x < 0) this.pos.x = width;
if (this.pos.y > height) this.pos.y = 0;
if (this.pos.y < 0) this.pos.y = height;
}
align(boids) {
let perception = 50;
let steering = createVector();
let total = 0;
for (let other of boids) {
let d = dist(this.pos.x, this.pos.y, other.pos.x, other.pos.y);
if (other != this && d < perception) {
steering.add(other.vel);
total++;
}
}
if (total > 0) {
steering.div(total);
steering.setMag(this.maxSpeed);
steering.sub(this.vel);
steering.limit(this.maxForce);
}
return steering;
}
cohesion(boids) {
let perception = 50;
let steering = createVector();
let total = 0;
for (let other of boids) {
let d = dist(this.pos.x, this.pos.y, other.pos.x, other.pos.y);
if (other != this && d < perception) {
steering.add(other.pos);
total++;
}
}
if (total > 0) {
steering.div(total);
steering.sub(this.pos);
steering.setMag(this.maxSpeed);
steering.sub(this.vel);
steering.limit(this.maxForce);
}
return steering;
}
separation(boids) {
let perception = 24;
let steering = createVector();
let total = 0;
for (let other of boids) {
let d = dist(this.pos.x, this.pos.y, other.pos.x, other.pos.y);
if (other != this && d < perception) {
let diff = p5.Vector.sub(this.pos, other.pos);
diff.div(d * d);
steering.add(diff);
total++;
}
}
if (total > 0) {
steering.div(total);
steering.setMag(this.maxSpeed);
steering.sub(this.vel);
steering.limit(this.maxForce);
}
return steering;
}
flock(boids) {
let alignment = this.align(boids);
let cohesion = this.cohesion(boids);
let separation = this.separation(boids);
// ๊ฐ ๊ท์น์ ์ํฅ ๊ฐ์ค์น
separation.mult(1.5);
alignment.mult(1.0);
cohesion.mult(1.0);
this.acc.add(alignment);
this.acc.add(cohesion);
this.acc.add(separation);
}
update() {
this.pos.add(this.vel);
this.vel.add(this.acc);
this.vel.limit(this.maxSpeed);
this.acc.mult(0);
}
show() {
strokeWeight(6);
stroke(150, 255, 30);
point(this.pos.x, this.pos.y);
}
}
๐ ํต์ฌ ๊ฐ๋
์๋๋ 5~10๋ฒ ์์ฃผ์ ์ ์๊ฐ์ ๋๋ค. ์ฝ๋๋ ์ถํ ์ถ๊ฐํ ์์ ์ ๋๋ค.