Astral Republic

✱ LABORATORY · Experiment

Boids — How Does a School of Fish Move as One Body

Just three rules, and hundreds of them gather and scatter as if alive. Try tuning the weights yourself.

🔍 What is this?

When a school of fish or a flock of birds ripples and moves as if it were one body, no one is conducting it. Each one just looks at its neighbors and follows a few identical rules — yet the whole thing becomes a living flock. Craig Reynolds proved this in 1986 with “Boids.”

⚙️ How it works — exactly three rules

  1. Separation — steer slightly away from neighbors that are too close (avoid collisions).
  2. Alignment — match your heading to the average direction of your neighbors.
  3. Cohesion — move toward the center of your neighbors.

Just the balance of weights between these three completely changes the flock’s character.

▶️ Try it yourself

Crank up cohesion and they clump into one blob; crank up separation and they scatter. Drop alignment to zero and it’s every fish for itself — not a flock, just dots.

💡 Click in the water — toss in some bait, ripples spread, and the fish rush over in a swarm. Once it’s eaten, they go back to their own ways.

● LIVE DEMO직접 만져보세요

🛠 My reproduction

That’s the whole thing: each fish scans its neighbors within a radius every frame and adds up three forces (separation, alignment, cohesion). I exposed the weights as sliders, rotated each fish toward its heading, and swung the tail fin left-right with a sin to give a swimming feel.

for (const o of neighbors) {
  separation += away(b, o) * sepW;   // push away if too close
  alignment  += o.velocity * aliW;   // follow the neighbors' average direction
  cohesion   += (center - b.pos) * cohW; // gather toward the flock center
}
velocity += separation + alignment + cohesion;

The bait interaction — a click creates bait and ripples at that spot and adds a strong pull toward it for every fish. Fish that get close nibble the bait away (life decreases); once it’s gone, the pull releases and, with only the three rules left, they scatter back into the flock.

if (food) {
  velocity += toward(food) * 0.5;     // swarm toward the bait
  if (dist(b, food) < 14) food.life -= 3; // nearby fish eat it away
}

📝 Takeaways

The core idea is “order emerges from rules alone, with no central control.” Toss in a single piece of bait and the whole flock rushes in and scatters — nobody ordered it, yet it feels natural. It’s striking that dropping just the alignment weight to zero instantly kills the sense of a “flock.” Game AI (crowds, fish), drone swarms, and crowd simulations are all cousins of this.

📤Share𝕏Reddit

🧪 Related experiments