• fullscreen
  • Boid.pde
  • BoidList.pde
  • Flock.pde
  • class Boid {
      InteractiveAvatarFrame frame;
      Quaternion q;
      int grabsMouseColor;//color
      int avatarColor;
    
      // fields
      PVector pos, vel, acc, ali, coh, sep; // pos, velocity, and acceleration in
      // a vector datatype
      float neighborhoodRadius; // radius in which it looks for fellow boids
      float maxSpeed = 4; // maximum magnitude for the velocity vector
      float maxSteerForce = .1f; // maximum magnitude of the steering vector
      float hue; // hue
      float sc = 3; // scale factor for the render of the boid
      float flap = 0;
      float t = 0;
      boolean avoidWalls = false;
    
      // constructors
      Boid(PVector inPos) {
        grabsMouseColor = color(0,0,255);
        avatarColor = color(255,0,0);		
        pos = new PVector();
        pos.set(inPos);
        frame = new InteractiveAvatarFrame(scene);	
        frame.setPosition(pos);
        frame.setAzimuth(-HALF_PI);
        frame.setTrackingDistance(scene.radius()/10);
        vel = new PVector(random(-1, 1), random(-1, 1), random(1, -1));
        acc = new PVector(0, 0, 0);
        neighborhoodRadius = 100;
      }
    
      Boid(PVector inPos, PVector inVel, float r) {
        grabsMouseColor = color(0,0,255);
        avatarColor = color(255,0,0);
        pos = new PVector();
        pos.set(inPos);
        frame = new InteractiveAvatarFrame(scene);
        frame.setPosition(pos);
        frame.setAzimuth(-HALF_PI);
        frame.setTrackingDistance(scene.radius()/10);
        vel = new PVector();
        vel.set(inVel);
        acc = new PVector(0, 0);
        neighborhoodRadius = r;
      }
    
      void run(ArrayList bl) {
        t += .1;
        flap = 10 * sin(t);
        // acc.add(steer(new PVector(mouseX,mouseY,300),true));
        // acc.add(new PVector(0,.05,0));
        if (avoidWalls) {
          acc.add(PVector.mult(avoid(new PVector(pos.x, flockHeight, pos.z), true), 5));
          acc.add(PVector.mult(avoid(new PVector(pos.x, 0, pos.z), true), 5));
          acc.add(PVector.mult(avoid(new PVector(flockWidth, pos.y, pos.z),	true), 5));
          acc.add(PVector.mult(avoid(new PVector(0, pos.y, pos.z), true), 5));
          acc.add(PVector.mult(avoid(new PVector(pos.x, pos.y, 0), true), 5));
          acc.add(PVector.mult(avoid(new PVector(pos.x, pos.y, flockDepth), true), 5));
        }
        flock(bl);
        move();
        checkBounds();
        render();
      }
    
      // ///-----------behaviors---------------
      void flock(ArrayList bl) {
        ali = alignment(bl);
        coh = cohesion(bl);
        sep = seperation(bl);
        acc.add(PVector.mult(ali, 1));
        acc.add(PVector.mult(coh, 3));
        acc.add(PVector.mult(sep, 1));
      }
    
      void scatter() {
    
      }
    
      // //------------------------------------
    
      void move() {
        vel.add(acc); // add acceleration to velocity
        vel.limit(maxSpeed); // make sure the velocity vector magnitude does not
        // exceed maxSpeed
        pos.add(vel); // add velocity to position
        frame.setPosition(pos);
        acc.mult(0); // reset acceleration
      }
    
      void checkBounds() {
        if (pos.x > flockWidth)
          pos.x = 0;
        if (pos.x < 0)
          pos.x = flockWidth;
        if (pos.y > flockHeight)
          pos.y = 0;
        if (pos.y < 0)
          pos.y = flockHeight;
        if (pos.z > flockDepth)
          pos.z = 0;
        if (pos.z < 0)
          pos.z = flockDepth;
      }
    
      // check if this boid's frame is the avatar
      boolean isAvatar() {
        if ( scene.avatar() == null )
          return false;
        if ( scene.avatar().equals(frame) )
          return true;
        return false;
      }
    
      void render() {
        pushStyle();
        stroke(hue);
        noFill();
        noStroke();
        fill(hue);		
    
        q = Quaternion.multiply(new Quaternion( new PVector(0,1,0),  atan2(-vel.z, vel.x)), 
                                new Quaternion( new PVector(0,0,1),  asin(vel.y / vel.mag())) );		
        frame.setRotation(q);
    
        pushMatrix();
        // Multiply matrix to get in the frame coordinate system.	
        frame.applyTransformation(scene.parent);		
    
        // highlight boids under the mouse
        if (frame.grabsMouse()) {
          fill( grabsMouseColor);
          // additionally, set the boid's frame as the avatar if the mouse is pressed
          if (mousePressed == true) 
            scene.setAvatar(frame);			
        }		
        if ( isAvatar() ) {
          fill( avatarColor );
        }
    
        //draw boid
        beginShape(TRIANGLES);
        vertex(3 * sc, 0, 0);
        vertex(-3 * sc, 2 * sc, 0);
        vertex(-3 * sc, -2 * sc, 0);
    
        vertex(3 * sc, 0, 0);
        vertex(-3 * sc, 2 * sc, 0);
        vertex(-3 * sc, 0, 2 * sc);
    
        vertex(3 * sc, 0, 0);
        vertex(-3 * sc, 0, 2 * sc);
        vertex(-3 * sc, -2 * sc, 0);
    
        vertex(-3 * sc, 0, 2 * sc);
        vertex(-3 * sc, 2 * sc, 0);
        vertex(-3 * sc, -2 * sc, 0);
        endShape();		
    
        popMatrix();
    
        popStyle();		
      }
    
      // steering. If arrival==true, the boid slows to meet the target. Credit to
      // Craig Reynolds
      PVector steer(PVector target, boolean arrival) {
        PVector steer = new PVector(); // creates vector for steering
        if (!arrival) {
          steer.set(PVector.sub(target, pos)); // steering vector points
          // towards target (switch
          // target and pos for
          // avoiding)
          steer.limit(maxSteerForce); // limits the steering force to
          // maxSteerForce
        } 
        else {
          PVector targetOffset = PVector.sub(target, pos);
          float distance = targetOffset.mag();
          float rampedSpeed = maxSpeed * (distance / 100);
          float clippedSpeed = min(rampedSpeed, maxSpeed);
          PVector desiredVelocity = PVector.mult(targetOffset,
          (clippedSpeed / distance));
          steer.set(PVector.sub(desiredVelocity, vel));
        }
        return steer;
      }
    
      // avoid. If weight == true avoidance vector is larger the closer the boid
      // is to the target
      PVector avoid(PVector target, boolean weight) {
        PVector steer = new PVector(); // creates vector for steering
        steer.set(PVector.sub(pos, target)); // steering vector points away from
        // target
        if (weight)
          steer.mult(1 / sq(PVector.dist(pos, target)));
        // steer.limit(maxSteerForce); //limits the steering force to
        // maxSteerForce
        return steer;
      }
    
      PVector seperation(ArrayList boids) {
        PVector posSum = new PVector(0, 0, 0);
        PVector repulse;
        for (int i = 0; i < boids.size(); i++) {
          Boid b = (Boid) boids.get(i);
          float d = PVector.dist(pos, b.pos);
          if (d > 0 && d <= neighborhoodRadius) {
            repulse = PVector.sub(pos, b.pos);
            repulse.normalize();
            repulse.div(d);
            posSum.add(repulse);
          }
        }
        return posSum;
      }
    
      PVector alignment(ArrayList boids) {
        PVector velSum = new PVector(0, 0, 0);
        int count = 0;
        for (int i = 0; i < boids.size(); i++) {
          Boid b = (Boid) boids.get(i);
          float d = PVector.dist(pos, b.pos);
          if (d > 0 && d <= neighborhoodRadius) {
            velSum.add(b.vel);
            count++;
          }
        }
        if (count > 0) {
          velSum.div((float) count);
          velSum.limit(maxSteerForce);
        }
        return velSum;
      }
    
      PVector cohesion(ArrayList boids) {
        PVector posSum = new PVector(0, 0, 0);
        PVector steer = new PVector(0, 0, 0);
        int count = 0;
        for (int i = 0; i < boids.size(); i++) {
          Boid b = (Boid) boids.get(i);
          float d = dist(pos.x, pos.y, b.pos.x, b.pos.y);
          if (d > 0 && d <= neighborhoodRadius) {
            posSum.add(b.pos);
            count++;
          }
        }
        if (count > 0) {
          posSum.div((float) count);
        }
        steer = PVector.sub(posSum, pos);
        steer.limit(maxSteerForce);
        return steer;
      }
    }
    
    class BoidList {
      ArrayList boids; // will hold the boids in this BoidList
      float h; // for color
    
      BoidList(int n, float ih) {
        boids = new ArrayList();
        h = ih;
        for (int i = 0; i < n; i++)
          boids.add(new Boid(new PVector(flockWidth/2, flockHeight/2, flockDepth/2 )));
      }
    
      void add() {
        boids.add(new Boid(new PVector(flockWidth/2, flockHeight/2)));
      }
    
      void addBoid(Boid b) {
        boids.add(b);
      }
    
      void run(boolean aW) {
        for (int i = 0; i < boids.size(); i++) // iterate through the list of
          // boids
        {
          Boid tempBoid = (Boid) boids.get(i); // create a temporary boid to
          // process and make it the
          // current boid in the list
          tempBoid.hue = h;
          tempBoid.avoidWalls = aW;
          tempBoid.run(boids); // tell the temporary boid to execute its run
          // method
        }
      }
    }
    
    /**
     * Flock
     * by Matt Wetmore. Adapted to proscene by Jean Pierre Charalambos. 
     * 
     * A more complex example which interactively enables the selection of a frame
     * "avatar" for the camera to follow.
     *
     * This example is inspired in the famous artificial life program "Boids",
     * initially developed by Craig Reynolds in 1986.
     * 
     * Boids under the mouse will be colored blue. If you click on a boid it will be
     * selected as the avatar, useful for the THIRD_PERSON proscene camera mode.
     * 
     * Click the space bar to switch between the different camera modes: ARCBALL,
     * WALKTHROUGH, and THIRD_PERSON.  When the camera is in THIRD_PERSON use the
     * following keys to control the camera position respect to the boid avatar:
     * 'c'/'C': azimuth; 'd'/'D': tracking distance, and; 't'/'T': inclination.
     * 
     * Press 'f' to toggle the drawing of the frames' visual hints.
     * 
     * Press 'h' to toggle the mouse and keyboard navigation help.
     */
    
    import remixlab.proscene.*;
    
    Scene scene;
    //flock bounding box
    int flockWidth = 1280;
    int flockHeight = 720;
    int flockDepth = 600;
    int initBoidNum = 300; // amount of boids to start the program with
    BoidList flock1;// ,flock2,flock3;
    boolean smoothEdges = false;
    boolean avoidWalls = true;
    
    void setup() {
      size(640, 360, P3D);  
      scene = new Scene(this);
      scene.background(180,250,250);
      scene.setAxisIsDrawn(false);
      scene.setGridIsDrawn(false);
      scene.setHelpIsDrawn(false);
      scene.setBoundingBox(new PVector(0,0,0), new PVector(flockWidth,flockHeight,flockDepth));
      scene.showAll();
      // create and fill the list of boids
      flock1 = new BoidList(initBoidNum, 255);
      // flock2 = new BoidList(100,255);
      // flock3 = new BoidList(100,128);
    }
    
    void draw() {
      //Proscene sets the background to black by default. If you need to change
      //it, don't call background() directly but use scene.background() instead
      //(which can be called in the setup or here at the beginning of your drawing).  
      ambientLight(128,128,128);
      directionalLight(255, 255, 255, 0, 1, -100);
      noFill();
      stroke(0);
    
      line(0, 0, 0, 0, flockHeight, 0);
      line(0, 0, flockDepth, 0, flockHeight, flockDepth);
      line(0, 0, 0, flockWidth, 0, 0);
      line(0, 0, flockDepth, flockWidth, 0, flockDepth);
    
      line(flockWidth, 0, 0, flockWidth, flockHeight, 0);
      line(flockWidth, 0, flockDepth, flockWidth, flockHeight, flockDepth);
      line(0, flockHeight, 0, flockWidth, flockHeight, 0);
      line(0, flockHeight, flockDepth, flockWidth, flockHeight, flockDepth);
    
      line(0, 0, 0, 0, 0, flockDepth);
      line(0, flockHeight, 0, 0, flockHeight, flockDepth);
      line(flockWidth, 0, 0, flockWidth, 0, flockDepth);
      line(flockWidth, flockHeight, 0, flockWidth, flockHeight, flockDepth);				
    
      flock1.run(avoidWalls);
      // flock2.run();
      // flock3.run();
      if (smoothEdges)
        smooth();
      else
        noSmooth();
    }
    
    void keyPressed() {
      switch (key) {
      case 'u':
        smoothEdges = !smoothEdges;
        break;
      case 'v':
        avoidWalls = !avoidWalls;
        break;
      }
    }
    

    code

    tweaks (0)

    about this sketch

    This sketch is running as Java applet, exported from Processing.

    license

    advertisement

    Jean Pierre Charalambos

    3d flock of boids with proscene

    Add to Faves Me Likey@! 3
    You must login/register to add this sketch to your favorites.

    3d flock of boids by <a href="http://www.openprocessing.org/visuals/?visualID=6910">Matt Wetmore</a>, ported to <a href="http://code.google.com/p/proscene/">proscene</a>.

    Boids under the mouse will be colored blue. If you click on a boid it will be selected as avatar, useful for the THIRD_PERSON camera mode.

    Click the space bar to switch between the different camera modes: ARCBALL, WALKTHROUGH, and THIRD_PERSON (the following keys control the camera position respect to the boid avatar: 'c'/'C': azimuth; 'd'/'D': tracking distance, and; 't'/'T': inclination).

    Press 'h' to toggle help.

    subpixel
    29 Jul 2010
    Changing to the point of view of one of the boids is cool. I like it!
    You need to login/register to comment.