美文网首页
转向行为结合

转向行为结合

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

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

    6.12 结合

    • 只通过一种行为规则无法模拟出复杂系统的自发行为。
    • 开发一种实现来自各种转向力的混合和匹配这种行为的机制

    1、回顾

    • 力的结合,在第2章做过这样的事。
    PVector wind = new PVector(0.001,0);
    PVector gravity = new PVector(0,0.1);
    mover.applyForce(wind);
    mover.applyForce(gravity);
    
    • 在以上代码中,mover对象同时受两个力的作用。该程序能正常工作,因为Mover类支持力的累加。

    2、转向力结合

      在本章中,力源自对象(小车)自身的意愿,我们希望这些意愿也可以累加。

      让我们从以下场景开始,假设系统中的小车有两个意愿:

    • 寻找鼠标所在的位置;
    • 和距离过近的其他小车分离。

      对此,我们可能会在Vehicle类中加入一个applyBehaviors()函数,用于管理小车的所有行为。

    void applyBehaviors(ArrayList<Vehicle> vehicles) {
          separate(vehicles);
          seek(new PVector(mouseX,mouseY));
    }
    
    • applyBehavior()函数调用了separate()函数和seek()函数,这两个函数分别对小车施加不同的转向力。
    • 我们想调整这两种转向力的强度,但现在的实现无法做到这一点。
    • separate()函数和seek()函数最好能返回转向力向量,如此一来,我们就可以调整转向力强度,最后用调整后的转向力影响小车的加速度。
    void applyBehaviors(ArrayList<Vehicle> vehicles) {
          PVector separate = separate(vehicles);
          PVector seek = seek(new PVector(mouseX,mouseY));
          applyForce(separate); 我们必须在这里施加转向力,因为seek()函数和separate()函数不再做这件
          applyForce(seek);
    }
    
    • 看看seek()函数的变化:
    PVector seek(PVector target) {
        PVector desired = PVector.sub(target,loc);
        desired.normalize();
        desired.mult(maxspeed);
        PVector steer = PVector.sub(desired,vel);
        steer.limit(maxforce);
        applyForce(steer); 不再施加转向力,而是返回转向力向量
        return steer;
    }
    
    • 这是一个细微的变化,但对我们来说非常重要:它使我们能集中改变多种转向力的强度。

    3、示例

    示例代码6-8 转向行为结合:寻找和分离

    ArrayList<Vehicle> vehicles;
    
    void setup() {
      size(640,360);
      // We are now making random vehicles and storing them in an ArrayList
      vehicles = new ArrayList<Vehicle>();
      for (int i = 0; i < 100; i++) {
        vehicles.add(new Vehicle(random(width),random(height)));
      }
    }
    
    void draw() {
      background(255);
    
      for (Vehicle v : vehicles) {
        // Path following and separation are worked on in this function
        v.applyBehaviors(vehicles);
        // Call the generic run method (update, borders, display, etc.)
        v.update();
        v.display();
      }
    
      // Instructions
      fill(0);
      text("Drag the mouse to generate new vehicles.",10,height-16);
    }
    
    
    void mouseDragged() {
      vehicles.add(new Vehicle(mouseX,mouseY));
    }
    

    Vehicle.pde

    class Vehicle {
    
      // All the usual stuff
      PVector position;
      PVector velocity;
      PVector acceleration;
      float r;
      float maxforce;    // Maximum steering force
      float maxspeed;    // Maximum speed
    
        // Constructor initialize all values
      Vehicle(float x, float y) {
        position = new PVector(x, y);
        r = 12;
        maxspeed = 3;
        maxforce = 0.2;
        acceleration = new PVector(0, 0);
        velocity = new PVector(0, 0);
      }
    
      void applyForce(PVector force) {
        // We could add mass here if we want A = F / M
        acceleration.add(force);
      }
      
      void applyBehaviors(ArrayList<Vehicle> vehicles) {
         PVector separateForce = separate(vehicles);
         PVector seekForce = seek(new PVector(mouseX,mouseY));
         separateForce.mult(2);
         seekForce.mult(1);
         applyForce(separateForce);
         applyForce(seekForce); 
      }
      
        // A method that calculates 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;
      }
    
      // Separation
      // Method checks for nearby vehicles and steers away
      PVector separate (ArrayList<Vehicle> vehicles) {
        float desiredseparation = r*2;
        PVector sum = new PVector();
        int count = 0;
        // For every boid in the system, check if it's too close
        for (Vehicle other : vehicles) {
          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
            sum.add(diff);
            count++;            // Keep track of how many
          }
        }
        // Average -- divide by how many
        if (count > 0) {
          sum.div(count);
          // Our desired vector is the average scaled to maximum speed
          sum.normalize();
          sum.mult(maxspeed);
          // Implement Reynolds: Steering = Desired - Velocity
          sum.sub(velocity);
          sum.limit(maxforce);
        }
        return sum;
      }
    
    
      // 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);
      }
    
      void display() {
        fill(175);
        stroke(0);
        pushMatrix();
        translate(position.x, position.y);
        ellipse(0, 0, r, r);
        popMatrix();
      }
    
    }
    

    4、运行结果

    相关文章

      网友评论

          本文标题:转向行为结合

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