それぞれの鳥は、
1. すべて同じ速さで飛ぶ。
2. 飛ぶ方向は、近くにいる鳥の向かっている方角の平均値とする。
という単純な原則とし、さらにプログラムを簡単にするため、
3. 立体空間ではなく平面上のシミュレーションとする。
4. 鳥同士はいくら近づいてもよい。重なってもかまわない。
とした。
シミュレーション結果の例。
いちおう鳥の群舞らしく見える。
この動画はループしていて、画面全体に鳥の散らばっている状態が最初で、群れが右上に消えていくところが最後。画面から消えた鳥はまっすぐに遠ざかり、もどって来ることはない。
地上の草むら、風、天敵などアイテムの追加や、鳥の飛行区域の限定など宿題。すべての鳥の方向がそろってしまうのもおもしろくないので、個々の鳥の飛行方向にゆらぎを与えること等も。
プログラムは Processing で書いた。
コードは次のとおり。要検討事項は多いが、とりあえず動いてる。
int canvasW = 400, canvasH = 400;
int population = 500;
float neighborhoud = 50;
float speed = 1.5;
Bird[] birds = new Bird[population];
class Bird {
float x, y, dir;
Bird(float tempX, float tempY, float tempDir) {
x = tempX;
y = tempY;
dir = tempDir;
}
void display() {
arc(x, y, 20, 20, dir-PI-0.2, dir-PI+0.2);
}
float newDir() {
float accumX = cos(dir), accumY = sin(dir);
for (int i = 0; i < population; i++) {
if (dist(x, y, birds[i].x, birds[i].y) < neighborhoud) {
accumX += cos(birds[i].dir);
accumY += sin(birds[i].dir);
}
}
return atan2(accumY, accumX);
}
}
void setup() {
size(canvasW, canvasH);
fill(0);
for (int i = 0; i < population; i++) {
birds[i] = new Bird(random(0, canvasW),
random(0, canvasH),
random(0, TWO_PI));
}
}
void draw() {
background(204);
for (int i = 0; i < population; i++) {
birds[i].display();
float newdir = birds[i].newDir();
birds[i].dir = newdir;
birds[i].x += speed * cos(newdir);
birds[i].y += speed * sin(newdir);
}
}
このプログラムの難点は、群れの行動に対する個々の鳥の影響度合いが平等でないことで、鳥(Bird オブジェクト)の配列 birds の先頭に近い鳥ほど影響力が大きい。「追記] atan2の使い方もいけない。