Showing posts with label processing. Show all posts
Showing posts with label processing. Show all posts

Sunday, June 14, 2015

鳥の群舞の簡単シミュレーション

鳥の群れが空を舞う様子をシミュレートしてみた。
それぞれの鳥は、

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の使い方もいけない。