KAgent example 2d flock

From KokkugiaWiki

in addition to the kAgent class this example has a world class to control the population of agents.

the world class holds an arrayList of all the agents and uses this array list to pass each agent to every other agent in order that they can interact.


applet - kAgent population


sketch

import kGeom.*;

kWorld world1;

void setup(){
    size(500,500);
    frameRate(30);
    smooth();
    
    world1 = new kWorld();

    for (int i = 0; i < 50; i++) {
      world1.addAgent(new kAgent(new kVec(random(500),random(500)), new kVec(random(-1,1),random(-1,1)), 5, 0.2));
    }
    
}

void draw(){
  background(125);
   
  world1.run();
  
}


kAgent

// simple 2D agent class - using code from dan shiffman
// roland snooks | kokkugia.com | 2007

class kAgent{
  
 kVec         acc;
 kVec         vel;
 kVec         pos;
 kVec         vec;
 float        maxVel;
 float        maxForce;
 float        wandertheta;

 // constructor
 kAgent(
     kVec _pos, 
     kVec _vec, 
     float _maxVel,
     float _maxForce){
   
   acc = new kVec(0,0);
   vel = new kVec(0,0);    
   pos = kVec.clone(_pos);
   vec = kVec.clone(_vec);
   maxVel = _maxVel;
   maxForce = _maxForce;
   
 }
 
 
 // calculates new location
 void update(ArrayList pop){  

    //this.wander();
    //this.seek(new kVec(mx,my));
    
    kVec sep = separate(pop);   // Separation
    kVec ali = align(pop);      // Alignment
    kVec coh = cohesion(pop);   // Cohesion
    
    // Arbitrarily weight these forces
    sep.scale(5.0);
    ali.scale(1.0);
    coh.scale(1.0);
    
    // Add the force vectors to acceleration
    acc.plus(sep);
    acc.plus(ali);
    acc.plus(coh);

    vel.plus(acc);
    vel.limit(maxVel);  
    pos.plus(vel);
    acc = new kVec(0,0);  // reset acc to 0 each iteration
    
    borders();
    render();
    
 }


 // seek
 void seek(kVec target) {
    acc.plus(steer(target));
 }
   

 // steer
 kVec steer(kVec target) {
    kVec steer;  // The steering vector
    target.minus(pos); 
    float distance = target.length();

    if (distance > 0) {
      target.normalize();
      target.scale(maxVel);
      target.minus(vel); 
      //steer = kVec.clone(target); 
      target.limit(maxForce); 

    } 
    else {
      target = new kVec(0,0);
    }
    return target;
  }

  void wander() {
    float wanderR = 16;         
    float wanderD = 60;         
    float change = 0.25;
    wandertheta += random(-change,change);     

    kVec circleloc = kVec.clone(vel); 
    circleloc.normalize();            
    circleloc.scale(wanderD);          
    circleloc.plus(pos);              

    kVec circleOffSet = new kVec(wanderR*cos(wandertheta),wanderR*sin(wandertheta));
    circleOffSet.plus(circleloc);
    acc.plus(steer(circleOffSet)); 

  }  


// separation
  kVec separate (ArrayList pop) {
    float desiredseparation = 25.0;
    kVec sum = new kVec(0,0,0);
    int count = 0;

    for (int i = 0 ; i < pop.size(); i++) {
      kAgent other = (kAgent) pop.get(i);
      float dist = pos.distance(other.pos);
      
      // if the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself)
      if ((dist > 0) && (dist < desiredseparation)) {
        // calculate vector pointing away from neighbor
        kVec diff = kVec.clone(pos); 
        diff.minus(other.pos);
        diff.normalize();
        diff.scale(1/dist);          // weight by distance
        sum.plus(diff);
        count++;                     // keep track of how many
      }
    }
    // average -- divide by how many
    if (count > 0) {
      sum.scale(1/(float)count);
    }
    return sum;
  }
 
 
  // alignment
  kVec align (ArrayList pop) {
    float neighbordist = 50.0;
    kVec sum = new kVec(0,0,0);
    int count = 0;
    for (int i = 0 ; i < pop.size(); i++) {
      kAgent other = (kAgent) pop.get(i);
      float dist = pos.distance(other.pos);
      if ((dist > 0) && (dist < neighbordist)) {
        sum.plus(other.vel);
        count++;
      }
    }
    if (count > 0) {
      sum.scale(1/(float)count);
      sum.limit(maxForce);
    }
    return sum;
  }


  // cohesion
  kVec cohesion (ArrayList pop) {
    float neighbordist = 50.0f;
    kVec sum = new kVec(0,0,0);   
    int count = 0;
    for (int i = 0 ; i < pop.size(); i++) {
      kAgent other = (kAgent) pop.get(i);
      float dist = pos.distance(other.pos);
      if ((dist > 0) && (dist < neighbordist)) {
        sum.plus(other.pos); // Add location
        count++;
      }
    }
    if (count > 0) {
      sum.scale(1/(float)count);
      return steer(sum);  // steer towards the location
    }
    return sum;
  }


  void render() {
    fill(200);
    stroke(255);
    ellipse(pos.x,pos.y,10,10);
  }
  
  
  void borders() {
    if (pos.x < 0) pos.x = width;
    if (pos.y < 0) pos.y = height;
    if (pos.x > width) pos.x = 0;
    if (pos.y > height) pos.y = 0;
  }

}


kWorld

class kWorld {
  ArrayList population;
  
  kWorld() {
     population = new ArrayList(); // initialize the arraylist
  }

  // cycles through each agent passing the population to it
  void run(){
    for (int i = 0; i < population.size(); i++) {
      kAgent a = (kAgent) population.get(i);  
      a.update(population); 
    }
  }

  // add agent
  void addAgent(kAgent a) {
    population.add(a);
  }

}
Views