

Daniel
Shiffmanによる，Processingで鳥の群れ行動をシミュレートするプログラムがあります(<https://processing.org/examples/flocking.html>)．  
このプログラムに「マウスでクリックした場所に群れを向かわせる」といった機能を搭載したいのですが，どうすれば良いのかわかりません．どのように改良すれば，実現することができるでしょうか．ヒントでも良いので教えていただきたいです．

[code]

    Flock flock;
    
    void setup() {
      size(640, 360);
      flock = new Flock();
      // Add an initial set of boids into the system
      for (int i = 0; i < 150; i++) {
        flock.addBoid(new Boid(width/2,height/2));
      }
    }
    
    void draw() {
      background(50);
      flock.run();
    }
    
    // Add a new boid into the System
    void mousePressed() {
      flock.addBoid(new Boid(mouseX,mouseY));
    }
    
    
    
    // The Flock (a list of Boid objects)
    
    class Flock {
      ArrayList<Boid> boids; // An ArrayList for all the boids
    
      Flock() {
        boids = new ArrayList<Boid>(); // Initialize the ArrayList
      }
    
      void run() {
        for (Boid b : boids) {
          b.run(boids);  // Passing the entire list of boids to each boid individually
        }
      }
    
      void addBoid(Boid b) {
        boids.add(b);
      }
    
    }
    
    
    
    
    // The Boid class
    
    class Boid {
    
      PVector position;
      PVector velocity;
      PVector acceleration;
      float r;
      float maxforce;    // Maximum steering force
      float maxspeed;    // Maximum speed
    
        Boid(float x, float y) {
        acceleration = new PVector(0, 0);
    
        // This is a new PVector method not yet implemented in JS
        // velocity = PVector.random2D();
    
        // Leaving the code temporarily this way so that this example runs in JS
        float angle = random(TWO_PI);
        velocity = new PVector(cos(angle), sin(angle));
    
        position = new PVector(x, y);
        r = 2.0;
        maxspeed = 2;
        maxforce = 0.03;
      }
    
      void run(ArrayList<Boid> boids) {
        flock(boids);
        update();
        borders();
        render();
      }
    
      void applyForce(PVector force) {
        // We could add mass here if we want A = F / M
        acceleration.add(force);
      }
    
      // We accumulate a new acceleration each time based on three rules
      void flock(ArrayList<Boid> boids) {
        PVector sep = separate(boids);   // Separation
        PVector ali = align(boids);      // Alignment
        PVector coh = cohesion(boids);   // Cohesion
        // Arbitrarily weight these forces
        sep.mult(1.5);
        ali.mult(1.0);
        coh.mult(1.0);
        // Add the force vectors to acceleration
        applyForce(sep);
        applyForce(ali);
        applyForce(coh);
      }
    
      // Method to update position
      void update() {
        // Update velocity
        velocity.add(acceleration);
        // Limit speed
        velocity.limit(maxspeed);
        position.add(velocity);
        // Reset accelertion to 0 each cycle
        acceleration.mult(0);
      }
    
      // A method that calculates and applies a steering force towards a target
      // STEER = DESIRED MINUS VELOCITY
      PVector seek(PVector target) {
         PVector desired = PVector.sub(target, position);  // A vector pointing from the position to the target
        // Scale to maximum speed
        desired.normalize();
        desired.mult(maxspeed);
    
        // Above two lines of code below could be condensed with new PVector setMag() method
        // Not using this method until Processing.js catches up
        // desired.setMag(maxspeed);
    
        // Steering = Desired minus Velocity
        PVector steer = PVector.sub(desired, velocity);
        steer.limit(maxforce);  // Limit to maximum steering force
        return steer;
      }
    
      void render() {
        // Draw a triangle rotated in the direction of velocity
        float theta = velocity.heading2D() + radians(90);
        // heading2D() above is now heading() but leaving old syntax until Processing.js catches up
    
        fill(200, 100);
        stroke(255);
        pushMatrix();
        translate(position.x, position.y);
        rotate(theta);
        beginShape(TRIANGLES);
        vertex(0, -r*2);
        vertex(-r, r*2);
        vertex(r, r*2);
        endShape();
        popMatrix();
      }
    
      // Wraparound
      void borders() {
        if (position.x < -r) position.x = width+r;
        if (position.y < -r) position.y = height+r;
        if (position.x > width+r) position.x = -r;
        if (position.y > height+r) position.y = -r;
      }
    
      // Separation
      // Method checks for nearby boids and steers away
      PVector separate (ArrayList<Boid> boids) {
        float desiredseparation = 25.0f;
        PVector steer = new PVector(0, 0, 0);
        int count = 0;
        // For every boid in the system, check if it's too close
        for (Boid other : boids) {
          float d = PVector.dist(position, other.position);
          // If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself)
          if ((d > 0) && (d < desiredseparation)) {
            // Calculate vector pointing away from neighbor
            PVector diff = PVector.sub(position, other.position);
            diff.normalize();
            diff.div(d);        // Weight by distance
            steer.add(diff);
            count++;            // Keep track of how many
          }
        }
        // Average -- divide by how many
        if (count > 0) {
          steer.div((float)count);
        }
    
        // As long as the vector is greater than 0
        if (steer.mag() > 0) {
          // First two lines of code below could be condensed with new PVector setMag() method
          // Not using this method until Processing.js catches up
          // steer.setMag(maxspeed);
    
          // Implement Reynolds: Steering = Desired - Velocity
          steer.normalize();
          steer.mult(maxspeed);
          steer.sub(velocity);
          steer.limit(maxforce);
        }
        return steer;
      }
    
      // Alignment
      // For every nearby boid in the system, calculate the average velocity
      PVector align (ArrayList<Boid> boids) {
        float neighbordist = 50;
        PVector sum = new PVector(0, 0);
        int count = 0;
        for (Boid other : boids) {
          float d = PVector.dist(position, other.position);
          if ((d > 0) && (d < neighbordist)) {
            sum.add(other.velocity);
            count++;
          }
        }
        if (count > 0) {
          sum.div((float)count);
          // First two lines of code below could be condensed with new PVector setMag() method
          // Not using this method until Processing.js catches up
          // sum.setMag(maxspeed);
    
          // Implement Reynolds: Steering = Desired - Velocity
          sum.normalize();
          sum.mult(maxspeed);
          PVector steer = PVector.sub(sum, velocity);
          steer.limit(maxforce);
          return steer;
        } 
        else {
           return new PVector(0, 0);
        }
      }
    
      // Cohesion
      // For the average position (i.e. center) of all nearby boids, calculate steering vector towards that position
      PVector cohesion (ArrayList<Boid> boids) {
        float neighbordist = 50;
        PVector sum = new PVector(0, 0);   // Start with empty vector to accumulate all positions
        int count = 0;
        for (Boid other : boids) {
          float d = PVector.dist(position, other.position);
          if ((d > 0) && (d < neighbordist)) {
            sum.add(other.position); // Add position
            count++;
          }
        }
        if (count > 0) {
          sum.div(count);
          return seek(sum);  // Steer towards the position
        } 
        else {
          return new PVector(0, 0);
        }
      }
    }
    
[/code]


CC BY-SA 4.0
2020-06-14T05:34:13.703
67643
2020-06-14T08:34:37.903
2020-06-14T06:03:52.010
19110
20022
question
java processing
Boids(Flocking)プログラムにマウスクリックで群れの方向を与える


このプログラムでは、各 Boid にかかる仮想的な力を `flock` 関数で計算し、その値を元に各 Boid
が次の瞬間どこに動くかを計算しています。このためたとえば、マウスカーソルの方向に向けた力を `flock` 関数に追加すれば所望の動作を実現できます。

おおよそ次のようにすれば良いです：

  * 現在はクリックしたら Boid をひとつ追加するようになっており、動作確認の邪魔なのでこれを除去。
  * カーソルの座標 `new PVector(mouseX, mouseY)` に向けた力を計算する関数を定義する。`target` という便利な関数が定義されているのでこれを使う。
  * 上で定義した力を `applyForce` する処理を `flock` 関数に加える。


CC BY-SA 4.0
2020-06-14T08:34:37.903
67652
2020-06-14T08:34:37.903
19110
67643
answer