KAgent example 3d subFlock

From KokkugiaWiki

a simple flocking agent example with predator and prey agent sub-classes


applet - kAgent 3d subFlock


predator


class kAgentPredator extends kAgent{
   
 kAgentPredator(     
     kVec _pos, 
     kVec _vec, 
     float _maxVel,
     float _maxForce){
       
  super(
     _pos, 
     _vec, 
     _maxVel,
     _maxForce);
     
     drawColor = 0;
     agentType = "kAgentPredator";
  }
 
 
  void updatePop(ArrayList pop){  
    
   // seek pray
   // find closest agent
   float closestDist = envSize*envSize;
   int closestAgent = 0;
   for(int i = 0; i<pop.size(); i++){
     kAgent other = (kAgent) pop.get(i);
     if(other.agentType == "kAgentPrey"){
       float dist = pos.distance(other.pos);
       if(i > 0){
         if(dist < closestDist){
           closestDist = dist;
           closestAgent = i;
         }
           
       }else{
         closestDist = dist;
         closestAgent = 0;
       }
     }

   }
    
    // seek closest agent
    kAgent other = (kAgent) pop.get(closestAgent);
    kVec target = kVec.clone(other.pos);
    
    this.seek(target, 300);
  } 
 
 
   void render() {

    // draw vectors  
    float vecDisScale = 2;
    
    kLine ln = new kLine(pos, vel, vel.length()*vecDisScale);
    ln.setColor(255,0,0);
    space.append(ln);

    kLine ln1 = new kLine(pos, sumSep, sumSep.length()*vecDisScale);
    ln1.setColor(0,0,255);
    //space.append(ln1);
    
    // draw agent
    kLine ln2 = new kLine(pos, vel, 3);
    ln2.setColor(0);
    space.append(ln2);

  }
  
}


prey


class kAgentPrey extends kAgent{
   
 kAgentPrey(     
     kVec _pos, 
     kVec _vec, 
     float _maxVel,
     float _maxForce){
       
  super(
     _pos, 
     _vec, 
     _maxVel,
     _maxForce);
     
     drawColor = 255;
     agentType = "kAgentPrey";
  }
 
  
   void updatePop(ArrayList pop){  
    
    kVec predFlee = this.preditorFlee(pop);
     
    // call population functions
    kVec sep = separate(pop);   
    kVec ali = align(pop);      
    kVec coh = cohesion(pop);   
    
    // weight vector
    sep.scale(sepScale);
    ali.scale(aliScale);
    coh.scale(cohScale);
    
    predFlee.scale(10);
    
    // add the vectors to acceleration
    acc.plus(sep);
    acc.plus(ali);
    acc.plus(coh);
    
    acc.minus(predFlee);
  } 
  
  kVec preditorFlee(ArrayList pop){
   // find closest agent
   float closestDist = envSize*envSize;
   int closestAgent = 0;
   for(int i = 0; i<pop.size(); i++){
     kAgent other = (kAgent) pop.get(i);
     if(other.agentType == "kAgentPredator"){
       float dist = pos.distance(other.pos);
       if(i > 0){
         if(dist < closestDist){
           closestDist = dist;
           closestAgent = i;
         }
           
       }else{
         closestDist = dist;
         closestAgent = 0;
       }
     }

   }
    
    // seek closest agent
    kAgent other = (kAgent) pop.get(closestAgent);
    kVec target = kVec.clone(other.pos);
    return this.steer(target, 100); 
  
  }
   
}


sketch


import kGeom.*;
import kRender.*;

kSpace space;

kWorld world1;
float envSize = 300;

void setup(){
  size(500,500,P3D);
  frameRate(50);
  
  space = new kSpace(this);
  space.cam.jump(-600,-550,-500);
  
  world1 = new kWorld();
    
  // create agents
  for (int i = 0; i < 300; i++) {
    world1.addAgent(new kAgentPrey(new kVec(random(-250,250),random(-250,250),random(-250,250)), new kVec(random(-1,1),random(-1,1),random(-1,1)), 4, 0.2));
  }
    
  for (int i = 0; i < 10; i++) {
    world1.addAgent(new kAgentPredator(new kVec(random(-250,250),random(-250,250),random(-250,250)), new kVec(random(-1,1),random(-1,1),random(-1,1)), 12, 0.06));
  }
    
}


void draw(){
  
  background(255);

  int mx = mouseX;
  int my = mouseY;
   
  world1.run();
  
  kRange rng = new kRange(300);
  rng.setColor(100); 
  space.append(rng);
  
  space.render();
  space.init();
  
}


void mouseDragged(){
  space.mouseDragged();
}



kAgent

// simple 3D agent class - based on code from dan shiffman
// roland snooks | kokkugia.com | 2007


class kAgent{
  
 kVec         acc;
 kVec         vel;
 kVec         pos;
 kVec         vec;
 float        maxVel;
 float        maxForce;
 float        sepScale;
 float        aliScale;
 float        cohScale;
 float        rangeOfVision;

 float        wandertheta;
 
 float        attOffset = 200;
 float        ht = envSize*2;
 int          drawColor;
   
 String       agentType = "kAgent";
 
 kVec sumSep = new kVec(0,0,0);
 
 // constructor simple
 kAgent(
     kVec _pos, 
     kVec _vec, 
     float _maxVel,
     float _maxForce){
   
   acc = new kVec(0,0,0);
   vel = new kVec(random(-1,1),random(-1,1),random(-1,1));    
   pos = kVec.clone(_pos);
   vec = kVec.clone(_vec);
   maxVel = _maxVel;
   maxForce = _maxForce;
   
   sepScale = 7;
   aliScale = 0.7;
   cohScale = 1;
    
   rangeOfVision = 70; 

   drawColor = 255;
   
 }
 
 // constructor complete
  kAgent(
     kVec _pos, 
     kVec _vec, 
     float _maxVel,
     float _maxForce,
     kVec _vel,
     float _sepScale,
     float _aliScale,
     float _cohScale,
     float _rangeOfVision){
   
   acc = new kVec(0,0,0);
   vel = kVec.clone(_vel);    
   pos = kVec.clone(_pos);
   vec = kVec.clone(_vec);
   maxVel = _maxVel;
   maxForce = _maxForce;
   
   sepScale = _sepScale;
   aliScale = _aliScale;
   cohScale = _cohScale;
    
   rangeOfVision = _rangeOfVision; 
   drawColor = 255;
 }
 
 
 // calculates new location
 void step(kWorld world){ 
   
    updatePop(world.population);
    
    vel.plus(acc);
    vel.limit(maxVel);  
    pos.plus(vel);
    acc = new kVec(0,0,0);  // reset acc to 0 each iteration
    
    borders(envSize);
    render();
    
 }
 
 
 void updatePop(ArrayList pop){  
    
    // call population functions
    kVec sep = separate(pop);   
    kVec ali = align(pop);      
    kVec coh = cohesion(pop);   
    
    // weight vector
    sep.scale(sepScale);
    ali.scale(aliScale);
    coh.scale(cohScale);
    
    // add the vectors to acceleration
    acc.plus(sep);
    acc.plus(ali);
    acc.plus(coh);
    
  }    
 
 

 // steer
 kVec steer(kVec target, float threshold) {
    target.minus(pos); 
    float dist = target.length();

    if (dist > 0 && dist < threshold) {
      target.normalize();
      target.scale(maxVel);
      target.minus(vel); 
      target.limit(maxForce); 
    } 
    else {
      target = new kVec(0,0,0);
    }
    return target;
  }


  // seek
  void seek(kVec target, float threshold) {
    acc.plus(steer(target, threshold));
  }
   
   
  // flee  
  void flee(kVec target, float threshold){
    acc.minus(steer(target, threshold));
  }   
  
  
  // wander - currently only working in 2d
  void wander() {
    // make this 3D
    float wanderR = 8;         
    float wanderD = 60;         
    float change = 0.1;
    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, ht)); 
  }  


// separation
  kVec separate (ArrayList pop) {
    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 < rangeOfVision/1.5)) {
        kVec diff = kVec.clone(pos); 
        diff.minus(other.pos);
        diff.normalize();
        diff.scale(1/dist);          
        sum.plus(diff);
        count++;                     
      }
    }
    if (count > 0) {
      sum.scale(1/(float)count);
    }
    sumSep = kVec.clone(sum);
    return sum;
  }
 
 
  // alignment
  kVec align (ArrayList pop) {
    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 < rangeOfVision)) {
        sum.plus(other.vel);
        count++;
      }
    }
    if (count > 0) {
      sum.scale(1/(float)count);
      sum.limit(maxForce);
    }
    return sum;
  }


  // cohesion
  kVec cohesion (ArrayList pop) {
    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 < rangeOfVision)) {
        sum.plus(other.pos); 
        count++;
      }
    }
    if (count > 0) {
      sum.scale(1/(float)count);
      return steer(sum, ht);
    }
    return sum;
  }


  void render() {

    // draw vectors  
    float vecDisScale = 2;
    
    kLine ln = new kLine(pos, vel, vel.length()*vecDisScale);
    ln.setColor(255,0,0);
    space.append(ln);

    kLine ln1 = new kLine(pos, sumSep, sumSep.length()*vecDisScale);
    ln1.setColor(0,0,255);
    //space.append(ln1);
    
    // draw agent
    kLine ln2 = new kLine(pos, vel, 3);
    ln2.setColor(drawColor);
    space.append(ln2);

  }
  
  
  void borders(float envSize) {
    if (pos.x < -envSize) pos.x = envSize;
    if (pos.y < -envSize) pos.y = envSize;
    if (pos.z < -envSize) pos.z = envSize;
    if (pos.x > envSize) pos.x = -envSize;
    if (pos.y > envSize) pos.y = -envSize;
    if (pos.z > envSize) pos.z = -envSize;
    
  }

}

Views