• 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

    Report Sketch

    Report for inappropriate content

    Please provide details if possible:

    Your have successfully reported the sketch. Thank you very much for helping to keep OpenProcessing clean and tidy :)

    Make a Copyright Infringement claim

    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.