群集

作者: 大龙10 | 来源:发表于2022-07-13 15:06 被阅读0次

    书名:代码本色:用编程模拟自然系统
    作者:Daniel Shiffman
    译者:周晗彬
    ISBN:978-7-115-36947-5
    第6章目录

    6.13 群集

    1、群集行为

    • 群集是动物的群体性行为,许多生物都有这种特性,比如鸟类、鱼类和昆虫。1986年,Craig Reynolds用计算机模拟了群集行为,并将算法写在自己的论文中。

    2、群集行为的模拟:

    • 1.我们会用转向力计算公式(转向力 = 所需速度 - 当前速度)实现群集的规则。
    • 2.这些转向力将由群体行为产生,小车要根据所有其他小车的状态计算转向力。
    • 3.我们需要结合多个转向力,并对它们进行加权。
    • 4.模拟结果是一个复杂系统——智能的群体行为将从简单的群集规则中产生,系统中没有控制中心和领导者。

    我们已经完成了前3点,本节的重心在于把它们结合在一起,观察最后的运行结果。

    3、群集的3个规则。

    • 1.分离(又叫“躲避”) 避免与邻居发生碰撞。
    • 2.对齐(又叫“复制”) 转向力的方向和邻居保持一致。
    • 3.聚集(又叫“集中”) 朝着邻居的中心转向(留在群体内)。


    4、Boid对象

    Boid对象描述群集系统中的元素,我们希望Boid对象也有一个函数管理所有上述行为,我们把这个函数称为flock()函数。

    void flock(ArrayList<Boid> boids) {
        PVector sep = separate(boids); 3种群集规则
        PVector ali = align(boids);
        PVector coh = cohesion(boids);
        sep.mult(1.5); 3种转向力的权重(尝试使用不同的值!)
        ali.mult(1.0);
        coh.mult(1.0);
        applyForce(sep); 施加转向力
        applyForce(ali);
        applyForce(coh);
    }
    

    5、示例

    示例代码6-9 群集

    Flock flock;
    
    void setup() {
      size(640,360);
      flock = new Flock();
      // Add an initial set of boids into the system
      for (int i = 0; i < 200; i++) {
        Boid b = new Boid(width/2,height/2);
        flock.addBoid(b);
      }
    }
    
    void draw() {
      background(255);
      flock.run();
      
      // Instructions
      fill(0);
      text("Drag the mouse to generate new boids.",10,height-16);
    }
    
    // Add a new boid into the System
    void mouseDragged() {
      flock.addBoid(new Boid(mouseX,mouseY));
    }
    

    Flock .pde

    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);
      }
    
    }
    

    Boid.pde

    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);
        velocity = new PVector(random(-1,1),random(-1,1));
        position = new PVector(x,y);
        r = 3.0;
        maxspeed = 3;
        maxforce = 0.05;
      }
    
      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
        // Normalize desired and scale to maximum speed
        desired.normalize();
        desired.mult(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);
        fill(175);
        stroke(0);
        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) {
          // 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);
          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);
        }
      }
    }
    

    6、运行结果

    相关文章

      网友评论

          本文标题:群集

          本文链接:https://www.haomeiwen.com/subject/fdpabrtx.html