日常の進捗

主に自分のための,行為とその習慣化の記録

回遊

久しぶりにそこそこ長く書いた。とはいえ、コードの殆どはProcessing公式のフロッキングのサンプルをベースにしてる。

Flocking \ Examples \ Processing.org

  • マウス:増える
  • キーボード:方向のランダム化
Flock flock;
int num =150;
// setup関数 : 初回1度だけ実行される
void setup() {
  fullScreen(); // ウィンドウサイズを960px,540pxに
  colorMode(HSB, 360, 100, 100); // HSBでの色指定にする
  flock = new Flock();
  for (int i = 0; i < num; i++) {
    float x = random(width);
    float y = random(height);
    flock.addBoid(new Boid(x, y));
  }
  background(0,0,0);
}

// draw関数 : setup関数実行後繰り返し実行される
void draw() {
  fill(0,0,0,10);
  rect(0,0,width,height);
  flock.run();
}

void mousePressed() {
  for(int i = 0; i < 5; i = i + 1){
    flock.addBoid(new Boid(mouseX, mouseY));  
  }
}

void keyPressed(){
  flock.randomize();
  flock.addBoid(new Boid(mouseX,mouseY));
}

class Flock {
  ArrayList<Boid> boids = new ArrayList<Boid>();

  void addBoid(Boid b) {
    boids.add(b);
  }
  void run() {
    for (Boid b : boids) {
      b.run(boids);
    }
  }

  void randomize() {
    for (Boid b : boids) {
      b.randomize();
    }
  }
}

class Boid {
  PVector pos;
  PVector vel;
  PVector acc;
  float r;
  float maxForce;
  float maxSpeed;
  Boid(float x, float y) {
    pos = new PVector(x, y);
    //vel = PVector.random2D();
    float angle = random(360);
    float theta = radians(angle);
    vel = new PVector(cos(theta), sin(theta));
    acc = new PVector();
    int n = (int)random(0,3);
    r = map(n,0,3,0.5,3);
    maxForce = map(n,0,3,0.03,0.01);
    maxSpeed = map(n,0,3,2,0.5);
  }

  void run(ArrayList<Boid> boids) {
    flock(boids);
    update();
    borders();
    render();
  }  

  void flock(ArrayList<Boid> boids) {
    PVector sep = separate(boids);
    PVector ali = align(boids);
    PVector coh = cohesion(boids);
    sep.mult(1.5);
    ali.mult(1.0);
    coh.mult(1.0);
    applyForce(sep);
    applyForce(ali);
    applyForce(coh);
  }
  void applyForce(PVector f) {
    acc.add(f);
  }
  void update() {
    vel.add(acc);
    vel.limit(maxSpeed);
    pos.add(vel);
    acc.mult(0);
  }

  void borders() {
    if (pos.x < -r) pos.x = width + r;
    if (pos.x > width + r) pos.x = -r;
    if (pos.y < -r) pos.y = height + r;
    if (pos.y > height + r) pos.y = -r;
  }

  void render() {
    float angle = vel.heading2D();
    float theta = angle + radians(90);
    float hue = abs(degrees(angle)%360);
    fill(hue, 80, 100);
    noStroke();
    pushMatrix();
    translate(pos.x, pos.y);
    rotate(theta);
    beginShape(TRIANGLES);
    vertex(0, -r*2);
    vertex(-r, r*2);
    vertex(r, r*2);
    endShape();
    popMatrix();
  }
  PVector separate(ArrayList<Boid> boids) {
    float desiredSeparation = 25f;
    PVector steer = new PVector(0, 0);
    float count = 0;
    for (Boid other : boids) {
      float d = PVector.dist(pos, other.pos);
      if ((d > 0) && (d < desiredSeparation)) {
        PVector diff = PVector.sub(pos, other.pos);
        diff.normalize();
        diff.div(d);
        steer.add(diff);
        count++;
      }
    }
    if (count > 0) {
      steer.div(count);
    }
    if (steer.mag() > 0) {
      //steer.setMag(maxSpeed);
      steer.normalize();
      steer.mult(maxSpeed);
      steer.sub(vel);
      steer.limit(maxForce);
    }
    return steer;
  }
  PVector align(ArrayList<Boid> boids) {
    float neighbordist = 50;
    PVector sum = new PVector(0, 0);
    float count = 0;
    for (Boid other : boids) {
      float d = PVector.dist(pos, other.pos);
      if ((d > 0) && (d < neighbordist)) {
        sum.add(other.vel);
        count++;
      }
    }
    if (count > 0) {
      sum.div(count);
      sum.normalize();
      sum.mult(maxSpeed);
      PVector steer = PVector.sub(sum, vel);
      steer.limit(maxForce);
      return steer;
    } else {
      return new PVector();
    }
  }
  PVector cohesion(ArrayList<Boid> boids) {
    float neighbordist = 50;
    PVector sum = new PVector(0, 0);
    float count = 0;
    for (Boid other : boids) {
      float d = PVector.dist(pos, other.pos);
      if ((d > 0) && (d < neighbordist)) {
        sum.add(other.pos);
        count++;
      }
    }
    if (count > 0) {
      sum.div(count);
      return seek(sum);
    } else {
      return new PVector(0, 0);
    }
  }
  PVector seek(PVector target) {
    PVector desired = PVector.sub(target, pos);
    desired.normalize();
    desired.mult(maxSpeed);
    PVector steer = PVector.sub(desired, vel);
    steer.limit(maxForce);
    return steer;
  }
  void randomize() {
    float angle = random(360);
    float theta = radians(angle);
    vel = new PVector(cos(theta), sin(theta));
  }
}