• fullscreen
  • agent_7.pde
  • /*
      Weird Boids V2 by Tim Ganly 2010
      Based on work by Craig Reynolds.
    
      Click and hold the mouse to lure the boids.
    */
    
    ArrayList<Agent> agents;
    final int NUMBER_OF_AGENTS = 400;
    final int CALC_FREQ = 1;
    final color BG_COL = color(0,0,0);
    float nincAmount = 0.01;
    float avoidWallDist = 30;
    
    float ninc, nx, ny;
    
    PVector arbitraryFollow = new PVector(0,0,0);
    
    void setup() {
      size(740,400);
      smooth();
      strokeCap(ROUND);
      background(BG_COL);
      agents = new ArrayList<Agent>(NUMBER_OF_AGENTS);
      for(int i=0; i<NUMBER_OF_AGENTS; i++) {
        agents.add(new Agent(random(avoidWallDist,width-avoidWallDist),random(avoidWallDist,height-avoidWallDist), 0, 0, i%CALC_FREQ));
      }
      frameRate(24);
      noiseDetail(2,0.5);
    }
    
    void draw() {
      fill(0,0,0,20);
      noStroke();  
      rect(0,0,width,height);
      if(!mousePressed) {
        ninc += nincAmount;
        nx = noise(ninc) ;
        ny = noise(ninc+100) ;
        arbitraryFollow = new PVector(nx * width, ny * height, 0);
      }
      Agent a;  
      for(int i=0; i<NUMBER_OF_AGENTS; i++) {
        a = agents.get(i); //no need to cast here because we use generics
        a.step();
        a.move();
        a.draw();
      }
    }
    
    class Agent {
      //'steer' refers is to 'steering vector': a vector indicating the direction in which the agent desires to move 
      PVector loc, vel, overAllSteer, mouseSteer, seperationSteer, alignmentSteer, followingSteer, cohesionSteer, accel, desiredVel;
    
      Agent followee;
    
      private boolean isFollowing = false;
      static final float maxAccel = 2.0;
      static final float maxSpeed = 10.0;
      static final float perceptionRange = 30.0;
      static final float mouseSteerWeight = 1; //tendency to follow mouse (or randomly moving position)
      static final float seperateSteerWeight = 1000;
      static final float alignmentSteerWeight = 0.1;
      static final float followingSteerWeight = 1; //tendency to follow flock mates
      static final float cohesionSteerWeight = 2;
      static final float avoidWallSteerWeight = 400; 
      static final float switchOnFollowingChance = 0.0004;
      static final float switchOffFollowingChance = 0.02;  
      static final boolean avoidWalls = true;
      final float mass = random(1.4,2.4);
      final color AGENT_COLOR = color(255,100,0);
      final color AGENT_COLOR2 = color(random(75,200),random(200,255),random(0,255));
      int calcFreq;
      ArrayList<Agent> nearByAgents = new ArrayList<Agent>();
    
      Agent(float x, float y, float vx, float vy, int calcFreq) {
        this.loc = new PVector(x,y);
        this.vel = new PVector(vx,vy);
        this.mouseSteer = new PVector(0,0,0);
        this.accel = new PVector(0,0,0);
        this.calcFreq = calcFreq;
      }
    
      void move() {
        loc.add(vel);
    
        //constrain to the screen    
        if(loc.x < 0) {
          loc.x = 0;
          if(vel.x < 0) {
            vel.x *= -1;
          }
        }
        if(loc.x > width) {
          loc.x = width;
          if(vel.x > 0) {
            vel.x *= -1;
          }
        }
        if(loc.y < 0) {
          loc.y = 0;
          if(vel.y < 0) {
            vel.y *= -1;
          }
        }
        if(loc.y > height) {
          loc.y = height;
          if(vel.y > 0) {
            vel.y *= -1;
          }
        }
      }
    
      void step() {
        //the steering vector is the vector that joins the agent loc to the mouse.
        PVector followPoint = mousePressed ? new PVector(mouseX,mouseY) : arbitraryFollow;
        mouseSteer = getVectorToTarget(followPoint);
        mouseSteer.normalize();
        mouseSteer.mult(mousePressed ? mouseSteerWeight * 2 : mouseSteerWeight);
    
        //get nearby agents, but only on every CALC_FREQth frame.
        if(frameCount % CALC_FREQ == calcFreq) {
          nearByAgents = new ArrayList<Agent>();
          Iterator<Agent> itr = agents.iterator();
          Agent anAgent;
          float distTo;
          while(itr.hasNext()) {
            anAgent = itr.next();
            distTo = PVector.dist(loc,anAgent.loc);
            if(distTo <= perceptionRange && anAgent != this) {
              nearByAgents.add(anAgent);
            }
          }
    
          int s = nearByAgents.size(); 
    
          seperationSteer = s == 0 ? new PVector(0,0,0) : getSeperationVector(nearByAgents); 
          alignmentSteer = s == 0 || isFollowing  ? new PVector(0,0,0) : getAlignmentVector(nearByAgents);
          alignmentSteer.normalize();
          cohesionSteer = s == 0  || isFollowing  ? new PVector (0,0,0) : getCohesionVector(nearByAgents);
          cohesionSteer.normalize();
    
          followingSteer = s == 0 ? new PVector(0,0,0) : getFollowingVector(nearByAgents);
    
          PVector avoidWallSteer = new PVector(0,0,0);
    
          //avoid the walls?
          if(avoidWalls) {
            if(loc.y < avoidWallDist) {
              avoidWallSteer.add(new PVector(0,1));
            }
            if(loc.y > height - avoidWallDist) {
              avoidWallSteer.add(new PVector(0,-1));
            }
            if(loc.x < avoidWallDist) {
              avoidWallSteer.add(new PVector(1,0));
            }
            if(loc.x > width - avoidWallDist) {
              avoidWallSteer.add(new PVector(-1,0));
            }
          }
    
          //weight the vectors
          seperationSteer.mult(seperateSteerWeight);
          alignmentSteer.mult(alignmentSteerWeight);
          followingSteer.mult(followingSteerWeight);
          cohesionSteer.mult(cohesionSteerWeight);
          avoidWallSteer.mult(avoidWallSteerWeight);
    
          //overALlSteer is a representation of what vector the agent wants to be travelling in.
          //Let's assume they want to be travelling at maximum speed though. 
          overAllSteer = PVector.add(mouseSteer,seperationSteer);
          overAllSteer.add(alignmentSteer);
          overAllSteer.add(followingSteer);
          overAllSteer.add(cohesionSteer);
          overAllSteer.add(avoidWallSteer);
    
          //acceleration should be the difference between the current velocity and the overALlSteer vector
          //e.g. 'I want to accelerate to meet my desired velocity, and this is the acceleration vector I want!'
          desiredVel = PVector.sub(overAllSteer,vel);
          accel = desiredVel.get();
          accel.normalize();
          accel.mult(maxAccel);
        }
        
        //F = ma, a = F/m
        accel.div(mass);
    
        vel.add(accel);
        vel.limit(maxSpeed);
      }
    
      private PVector getFollowingVector(ArrayList<Agent> agents) {
    
        //decide to switch following or not.
        PVector result = new PVector(0,0,0);
        boolean switchedOn = false;
    
        //should I be following?
        if(random(0,1.0) < switchOnFollowingChance && isFollowing == false) {
          isFollowing = true;
          switchedOn = true;
        }
    
        if(!isFollowing) {
          return result;
        }
        else {
          //we are following, but are we following the same as last time?
          if(switchedOn == false) {
            result = getVectorToTarget(followee.loc);
          }
          //should I turn off following?
          if(random(0,1.0) < switchOffFollowingChance) {
            isFollowing = false;
          }
        }
    
        //pick another agent to follow if neccessary
        if(switchedOn) {
          do {
            followee = agents.get((int)random(0,agents.size()));
          }
          while(followee == this);
    
          result = getVectorToTarget(followee.loc);
        }
        return result;//PVector.sub(result,vel);
      }
    
      private PVector getVectorToTarget(PVector target) {
        return PVector.sub(target,loc);
      }
      /*
      Loop through all the agents supplied in the agents argument.
       */
      private PVector getSeperationVector(ArrayList<Agent> agents) {
        PVector overAllRepulsion = new PVector(0,0,0);
        Iterator<Agent> itr = agents.iterator();
        Agent anAgent;
        PVector repulsion;
        float distTo;
        while(itr.hasNext()) {
          anAgent = itr.next();
          distTo = PVector.dist(loc,anAgent.loc);
          repulsion = PVector.sub(loc,anAgent.loc);
          repulsion.normalize();
          //weight by inverse square.
          if(distTo != 0) {
            repulsion.mult(1.0/sq(distTo));
          }   //todo what if the dist to is 0? Both agents occupy the same space...
    
          overAllRepulsion.add(repulsion);
        }
        return overAllRepulsion;
      }
    
      private PVector getCohesionVector(ArrayList<Agent> agents) {
        PVector avLoc = new PVector(0,0,0);
        Iterator<Agent> itr = agents.iterator();
        Agent anAgent;
        while(itr.hasNext()) {
          anAgent = itr.next();
          avLoc = PVector.add(avLoc,anAgent.loc);
        }
        avLoc.div(agents.size());
        return getVectorToTarget(avLoc);
      }
    
      private PVector getAlignmentVector(ArrayList<Agent> agents) {
        PVector overAllAlignment = new PVector(0,0,0);
        Iterator<Agent> itr = agents.iterator();
        while(itr.hasNext()) {
          overAllAlignment.add(itr.next().vel);
        }
        return overAllAlignment;
      }
    
      void draw() {
        PVector leng = vel.get();
        float speed =  vel.mag();
        float alph = map(speed,0,maxSpeed,10,220);
        stroke(isFollowing ? AGENT_COLOR : AGENT_COLOR2,alph);
        strokeWeight(mass);
        beginShape(LINES);
        vertex(loc.x, loc.y);
        vertex(loc.x - leng.x, loc.y - leng.y);
        endShape();
      }
    }
    
    

    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

    Person A

    Weirder Boids

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

    Based on a previous sketch. A swarm of boids. Every now and then, an individual boid might get "angry" and decide to chase a flock-mate. They turn red when this happens.

    Click and hold the mouse to attract the boids.

    Based on work by Craig Reynolds.

    Person A
    28 Oct 2010
    Version with 2000 boids here:

    http://vimeo.com/16265172
    You need to login/register to comment.