Jordan Parsons
- Second Year Architect

Processing – Boid Steering v1

Posted By: Jordan Parsons

This is my attempt to create a class of creatures that I can manipulate with different forces and rules. I am doing this as a base to create a pattern for an upcoming project. I have the basics down, but the real trouble for me is collision detection, but I am working through it. I have followed a lot of tutorials, and I think I am getting close, but it’s still rather glitchy. See for yourself, grab the source and un-quote //collide(boids);. Any tips would be greatly appreciated, and source after the jump.

http://jordanparsons.com/processing/boid_steering_v1/

Boid Steering

Boid Steering:

flock flock;

void setup(){
  flock = new flock();
  size(700,700);
  background(0);
  for(int i=0; i < 100; i++){
    if(i<1){
      flock.addBoid(new boid(new PVector(width/2,height/2),2.0,.5,i,#0000ff,255));
    }else{
      flock.addBoid(new boid(new PVector(width/2,height/2),2.0,.5,i,125,255));
    }
  }
  smooth();
}
void draw(){
  background(0);

  flock.run();

}

Boid:

class boid{
  PVector loc, acc, vel;
  float r, maxforce, maxspeed, theata, l;
  int boidColor, strokeColor, id;

  boid(PVector l, float ms, float mf, int ident, int bc, int sc){
    acc = new PVector(0,0);
    vel = new PVector(random(-1,1),random(-1,1));
    loc = l.get();
    r=20;
    maxspeed = ms;
    maxforce = mf;
    boidColor = bc;
    strokeColor = sc;
    id=ident;
  }

  void run(ArrayList boids){
    flock(boids);
    update();
    edge();
    //collide(boids);
    render();
  }

  void flock(ArrayList boids){
    PVector wan, sep, mou, coh;
    mou = steer(new PVector(mouseX,mouseY),true);
    wan = steer(wander(),false);
    sep = separate(boids);
    coh = cohesion(boids);

    sep.mult(10);
    wan.mult(.5);
    mou.mult(1);
    coh.mult(.5);

    acc.add(sep);
    acc.add(wan);
    //acc.add(mou);
    acc.add(coh);
  }

  void edge(){
    if (loc.x < -r) loc.x = width+r;
    if (loc.y < -r) loc.y = height+r;
    if (loc.x > width+r) loc.x = -r;
    if (loc.y > height+r) loc.y = -r;
  }

  void update() {
    vel.add(acc);
    vel.limit(maxspeed);
    loc.add(vel);
    acc.mult(0);
  }

  void render(){
    theata = vel.heading2D()+PI/2;
    l=r*vel.mag();
    fill(boidColor);
    stroke(strokeColor);
    pushMatrix();
    translate(loc.x,loc.y);
    rotate(theata);
    noFill();
    /* beginShape(TRIANGLES);
     vertex(0,-r*2);
     vertex(-r,r*2);
     vertex(r,r*2);
     endShape();*/

    ellipseMode(CENTER);
    ellipse(0,0,r,r);
    stroke(boidColor);
    line(0,0,0,-r/1.5);

    popMatrix();
  }

  PVector steer(PVector target, boolean slow){
    PVector steer, desired;
    float d;
    desired = PVector.sub(target,loc);
    d = desired.mag();
    if(d>0){
      desired.normalize();
      if ((slow) && (d < 100.0f)){
        desired.mult(maxspeed*(d/100.0f));
      }
      else{
        desired.mult(maxspeed);
      }
      steer = PVector.sub(desired,vel);
      steer.limit(maxforce);
    }
    else{
      steer = new PVector(0,0);
    }
    return steer;
  }

  PVector wander(){
    float wanderR, wanderD, change, wandertheata;
    PVector circleloc, circleoffset,target;
    wandertheata=random(-90,90);
    wanderR=16;
    wanderD=60;
    change=.25;

    wandertheata+=random(-change,change);

    circleloc = vel.get();
    circleloc.normalize();
    circleloc.mult(wanderD);
    circleloc.add(loc);

    circleoffset = new PVector(wanderR*cos(wandertheata),wanderR*sin(wandertheata));
    target = PVector.add(circleloc,circleoffset);

    return target;
  }

  PVector separate(ArrayList boids){
    float desiredseparation = 2*r;
    PVector sum = new PVector(0,0);
    int count = 0;
    for(int i=0; i < boids.size(); i++){
      boid other = (boid) boids.get(i);
      float d = loc.dist(other.loc);
      if((d > 0) && (d < desiredseparation)){
        PVector diff = loc.sub(loc,other.loc);
        diff.normalize();
        diff.div(d);
        sum.add(diff);
        count++;
      }
    }
    if(count > 0){
      sum.div(count);
    }
    return sum;
  }
  void collide(ArrayList boids){
    float desiredseparation = r;
    PVector sum = new PVector(0,0);
    int count = 0;
    for(int i=0; i < boids.size(); i++){
      boid other = (boid) boids.get(i);
      float d = loc.dist(other.loc);
      if((d > 0) && (d < desiredseparation)){
        PVector diff = loc.sub(loc,other.loc);
        diff.normalize();
        diff.div(d);
        vel=diff.get();
      }
    }
  }

  PVector cohesion (ArrayList boids) {
    float neighbordist = r*2;
    PVector sum = new PVector(0,0);   // Start with empty vector to accumulate all locations
    int count = 0;
    for (int i = 0 ; i < boids.size(); i++) {
      boid other = (boid) boids.get(i);
      float d = loc.dist(other.loc);
      if ((d > 0) && (d < neighbordist)) {
        sum.add(other.loc); // Add location
        count++;
      }
    }
    if (count > 0) {
      sum.div((float)count);
      return steer(sum,false);  // Steer towards the location
    }
    return sum;
  }
}

flock:

class flock{
  ArrayList boids;

  flock(){
    boids = new ArrayList();
  }

  void run(){
    for(int i=0; i < boids.size(); i++){
      boid b = (boid) boids.get(i);
      b.run(boids);
    }
  }

  void addBoid(boid b){
    boids.add(b);
  }
}

No Comments »

No comments yet.

RSS feed for comments on this post. TrackBack URL

Leave a comment



© 2009 Jordan Parsons
Grab the feed