回遊
久しぶりにそこそこ長く書いた。とはいえ、コードの殆どは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)); } }