• fullscreen
  • control.pde
  • fish.pde
  • flock.pde
  • hammer.pde
  • jellyfish.pde
  • seaLife.pde
  • water.pde
  • whale.pde
  • void controlPanel(){
      int deltaX = 10;
      int deltaY = 10;
      int stepX = 85;
      int stepY = 20;
      
      cp5 = new ControlP5(this);
      cp5.hide();
    
      Slider nFishesSlider = cp5.addSlider("nFishes",0,500,nFishes,deltaX,deltaY,100,15);
      nFishesSlider.setCaptionLabel("Number or fishes");
      nFishesSlider.getCaptionLabel().align(ControlP5.RIGHT_OUTSIDE,CENTER).setPaddingX(10);
    
      Slider nJellysSlider = cp5.addSlider("nJellys",0,500,nJellys,deltaX,deltaY+stepY,100,15);
      nJellysSlider.setCaptionLabel("Number or jellys");
      nJellysSlider.getCaptionLabel().align(ControlP5.RIGHT_OUTSIDE,CENTER).setPaddingX(10);
    
      Slider nWhalesSlider = cp5.addSlider("nWhales",0,100,nWhales,deltaX,deltaY+2*stepY,100,15);
      nWhalesSlider.setCaptionLabel("Number or whales");
      nWhalesSlider.getCaptionLabel().align(ControlP5.RIGHT_OUTSIDE,CENTER).setPaddingX(10);
    
      Slider nHammersSlider = cp5.addSlider("nHammers",0,100,nHammers,deltaX,deltaY+3*stepY,100,15);
      nHammersSlider.setCaptionLabel("Number or hammers");
      nHammersSlider.getCaptionLabel().align(ControlP5.RIGHT_OUTSIDE,CENTER).setPaddingX(10);
        
      Slider repulsionDistSlider = cp5.addSlider("repulsionDist",0,300,repulsionDist,deltaX,deltaY+4*stepY,100,15);
      repulsionDistSlider.setCaptionLabel("Repulsion distance");
      repulsionDistSlider.getCaptionLabel().align(ControlP5.RIGHT_OUTSIDE,CENTER).setPaddingX(10);
        
      Slider alignDistSlider = cp5.addSlider("alignDist",0,300,alignDist,deltaX,deltaY+5*stepY,100,15);
      alignDistSlider.setCaptionLabel("Align distance");
      alignDistSlider.getCaptionLabel().align(ControlP5.RIGHT_OUTSIDE,CENTER).setPaddingX(10);
        
      Slider attractionDistSlider = cp5.addSlider("attractionDist",0,300,attractionDist,deltaX,deltaY+6*stepY,100,15);
      attractionDistSlider.setCaptionLabel("Attraction distance");
      attractionDistSlider.getCaptionLabel().align(ControlP5.RIGHT_OUTSIDE,CENTER).setPaddingX(10);
        
      Slider huntDistSlider = cp5.addSlider("huntDist",0,300,huntDist,deltaX,deltaY+7*stepY,100,15);
      huntDistSlider.setCaptionLabel("Hunt distance");
      huntDistSlider.getCaptionLabel().align(ControlP5.RIGHT_OUTSIDE,CENTER).setPaddingX(10);
        
      Slider limitDistSlider = cp5.addSlider("limitDist",0,300,limitDist,deltaX,deltaY+8*stepY,100,15);
      limitDistSlider.setCaptionLabel("Limit distance");
      limitDistSlider.getCaptionLabel().align(ControlP5.RIGHT_OUTSIDE,CENTER).setPaddingX(10);
        
      Slider maxVelSlider = cp5.addSlider("maxVel",0,10,maxVel,deltaX,deltaY+9*stepY,100,15);
      maxVelSlider.setCaptionLabel("Maximum velocity");
      maxVelSlider.getCaptionLabel().align(ControlP5.RIGHT_OUTSIDE,CENTER).setPaddingX(10);
    
      Toggle paintLimitsToggle = cp5.addToggle("paintLimits",paintLimits,deltaX,deltaY+10*stepY,15,15);
      paintLimitsToggle.setCaptionLabel("Show limits");
      paintLimitsToggle.getCaptionLabel().align(ControlP5.RIGHT_OUTSIDE,CENTER).setPaddingX(10);
    
      Toggle paintLinesToggle = cp5.addToggle("paintLines",paintLines,deltaX,deltaY+11*stepY,15,15);
      paintLinesToggle.setCaptionLabel("Show lines");
      paintLinesToggle.getCaptionLabel().align(ControlP5.RIGHT_OUTSIDE,CENTER).setPaddingX(10);
    
      Toggle paintDetailsToggle = cp5.addToggle("paintDetails",paintDetails,deltaX,deltaY+12*stepY,15,15);
      paintDetailsToggle.setCaptionLabel("Paint details");
      paintDetailsToggle.getCaptionLabel().align(ControlP5.RIGHT_OUTSIDE,CENTER).setPaddingX(10);
    }
    
    void controlEvent(ControlEvent theControlEvent){
      if(theControlEvent.isFrom("nFishes")){
        while(nFishes > fishes.size()){
          float posAngle = random(0,TWO_PI);
          float posMagnitude = random(0,limitDist);
          PVector pos = new PVector(0.5*width+posMagnitude*cos(posAngle),0.5*height+posMagnitude*sin(posAngle));
          float velAngle = random(0,TWO_PI);
          float velMagnitude = 1;
          PVector vel = new PVector(velMagnitude*cos(velAngle),velMagnitude*sin(velAngle));
          color col = color(50,50,155);
          float headSize = 7;
          Fish f = new Fish(pos,vel,col,headSize);
          fishes.add(f);
        }
      }
      if(theControlEvent.isFrom("nJellys")){
        while(nJellys > jellys.size()){
          float posAngle = random(0,TWO_PI);
          float posMagnitude = random(0,limitDist);
          PVector pos = new PVector(0.5*width+posMagnitude*cos(posAngle),0.5*height+posMagnitude*sin(posAngle));
          float velAngle = random(0,TWO_PI);
          float velMagnitude = 1;
          PVector vel = new PVector(velMagnitude*cos(velAngle),velMagnitude*sin(velAngle));
          color col = color(200,200,230,150);
          float headSize = random(8,11);
          int nArms = 4;
          int lengthArms = int(random(headSize*0.5,headSize*0.6));
          Jellyfish j = new Jellyfish(pos,vel,col,headSize,nArms,lengthArms);
          jellys.add(j);
        }
      }
      if(theControlEvent.isFrom("nWhales")){
        while(nWhales > whales.size()){
          float posAngle = random(0,TWO_PI);
          float posMagnitude = random(0,limitDist);
          PVector pos = new PVector(0.5*width+posMagnitude*cos(posAngle),0.5*height+posMagnitude*sin(posAngle));
          float velAngle = random(0,TWO_PI);
          float velMagnitude = 1;
          PVector vel = new PVector(velMagnitude*cos(velAngle),velMagnitude*sin(velAngle));
          color col = color(0);
          float headSize = random(8,11);
          Whale w = new Whale(pos,vel,col,headSize);
          whales.add(w);
        }
      }
      if(theControlEvent.isFrom("nHammers")){
        while(nHammers > hammers.size()){
          float posAngle = random(0,TWO_PI);
          float posMagnitude = random(0,limitDist);
          PVector pos = new PVector(0.5*width+posMagnitude*cos(posAngle),0.5*height+posMagnitude*sin(posAngle));
          float velAngle = random(0,TWO_PI);
          float velMagnitude = 1;
          PVector vel = new PVector(velMagnitude*cos(velAngle),velMagnitude*sin(velAngle));
          color col = color(100,100,100);
          float headSize = random(5,6);
          Hammer h = new Hammer(pos,vel,col,headSize);
          hammers.add(h);
        }
      }
      if(theControlEvent.isFrom("repulsionDist")){
        repulsionDistSqr = sq(repulsionDist);
      }
      if(theControlEvent.isFrom("alignDist")){
        alignDistSqr = sq(alignDist);
      }
      if(theControlEvent.isFrom("attractionDist")){
        attractionDistSqr = sq(attractionDist);
      }
      if(theControlEvent.isFrom("huntDist")){
        huntDistSqr = sq(huntDist);
      }
      if(theControlEvent.isFrom("limitDist")){
        limitDistSqr = sq(limitDist);
      }
    }
    
    void mousePressed() {
      cp5.show();
    }
    
    
    
    class Fish extends Flock{
      float headSize;
    
      Fish(PVector tempPos, PVector tempVel, color tempCol, float tempHeadSize){
        super(tempPos,tempVel,tempCol);
        headSize = tempHeadSize;
      }
    
      void paintDetail(){
        noStroke();
        fill(col);
    
        pushMatrix();
          translate(pos.x,pos.y);
          rotate(HALF_PI + atan2(vel.y,vel.x));
          beginShape();
            curveVertex(0,-0.5*headSize);
          
            curveVertex(0.2*headSize,0);
          
            curveVertex(0,1.5*headSize);
          
            curveVertex(-0.2*headSize,0);
          
            curveVertex(0,-0.5*headSize);
    
            curveVertex(0.2*headSize,0);
            curveVertex(0,1.5*headSize);
          endShape();
        popMatrix();
      }
    }
    
    
    class Flock{
      PVector pos;
      PVector vel;
      PVector acc;
      color col;
      boolean isClose;
      
      Flock(PVector tempPos, PVector tempVel, color tempCol){
        pos = tempPos.get();
        vel = tempVel.get();
        acc = new PVector(0,0);
        col = tempCol;
        isClose = false;
      }
    
      void update(){
        vel.add(acc); 
        vel.limit(maxVel);
        pos.add(vel); 
        acc.set(new PVector(0,0));
        vel.mult(0.99);
        if(vel.mag() < 1){
          vel.normalize();
        }
        //isClose = false;
      }
      
      void evaluateInteractions(ArrayList flocks, int n, boolean repulsionCond, boolean alignCond, boolean attractionCond, boolean huntedCond, boolean huntCond){
        for(int i = 0; i < n; i++){
          Flock f = (Flock) flocks.get(i);
          PVector posDir = PVector.sub(f.pos,pos);
          float distanceSqr = sq(posDir.x) + sq(posDir.y);
          if(repulsionCond){
            repulsion(posDir,distanceSqr);
          }
          if(alignCond){
            PVector velDir = f.vel.get();
            align(velDir,distanceSqr);
          }
          if(attractionCond){
            attraction(posDir,distanceSqr);
          }
          if(huntedCond){
            hunted(posDir,distanceSqr);
          }
          if(huntCond){
            hunt(posDir,distanceSqr);
          }
        }
      }
      
      void repulsion(PVector forceDir, float distSqr){  
        if(distSqr <= repulsionDistSqr && distSqr != 0){
          float distance = sqrt(distSqr);
          PVector force = forceDir.get();
          force.div(distance);
          force.mult(-1*(repulsionDist/distance - 1));
          acc.add(force);
          
          if(paintLines){
            strokeWeight(1);
            stroke(color(255,0,0));
            line(pos.x,pos.y,pos.x+forceDir.x,pos.y+forceDir.y);
            noStroke();
          }
        } 
      }
      
      void align(PVector forceDir, float distSqr){  
        if(distSqr > repulsionDistSqr && distSqr <= alignDistSqr){
          float distance = sqrt(distSqr);
          PVector force = forceDir.get();
          force.normalize();
          force.mult(0.1*0.5*(1-cos(TWO_PI*(distance-repulsionDist)/(alignDist-repulsionDist))));
          acc.add(force);
        } 
      }
    
      void attraction(PVector forceDir, float distSqr){  
        if(distSqr > alignDistSqr && distSqr < attractionDistSqr){
          float distance = sqrt(distSqr);
          PVector force = forceDir.get();
          force.div(distance);
          force.mult(0.01*0.5*(1-cos(TWO_PI*(distance-alignDist)/(attractionDist-alignDist))));
          acc.add(force);
        } 
      }
    
      void hunted(PVector forceDir, float distSqr){  
        if(distSqr < huntDistSqr){
          float distance = sqrt(distSqr);
          PVector force = forceDir.get();
          force.div(distance);
          force.mult(-0.5*(huntDist/distance - 1));
          acc.add(force);
          if(distance < 15){
            isClose = true;
          }
        } 
      }
    
      void hunt(PVector forceDir, float distSqr){  
        if(distSqr < huntDistSqr){
          float distance = sqrt(distSqr);
          PVector force = forceDir.get();
          force.div(distance);
          force.mult(0.2*(huntDist/distance - 1));
          acc.add(force);
          if(distance < 15){
            isClose = true;
          }
        } 
      }
    
      void keepClose(){  
        PVector force = new PVector((0.5*width)-pos.x,(0.5*height)-pos.y);
        float distSqr = sq(force.x) + sq(force.y);
        if(distSqr > limitDistSqr){
          float distance = sqrt(distSqr);
          force.div(distance);
          force.mult(1*(distance/limitDist));
          acc.add(force);
        }
      }
    
      void paint(){
        noStroke();
        fill(col);
        
        float ang = atan2(vel.y,vel.x);
        PVector v1 = new PVector(pos.x+8*cos(ang),pos.y+8*sin(ang));
        PVector v2 = new PVector(pos.x+4*cos(ang+radians(90+45)),pos.y+4*sin(ang+radians(90+45)));
        PVector v3 = new PVector(pos.x+4*cos(ang+radians(270-45)),pos.y+4*sin(ang+radians(270-45)));
        triangle(v1.x,v1.y,v2.x,v2.y,v3.x,v3.y);
      }
      
      void paintPoint(){
        stroke(col);
        strokeWeight(4);
        point(pos.x,pos.y);
        strokeWeight(1);
        noStroke();
      }
        
      void paintLimits(){
        noFill();
        strokeWeight(1);
        stroke(color(255,0,0));
        ellipse(pos.x,pos.y,2*repulsionDist,2*repulsionDist);
        stroke(color(0,255,0));
        ellipse(pos.x,pos.y,2*alignDist,2*alignDist);
        stroke(color(0,0,255));
        ellipse(pos.x,pos.y,2*attractionDist,2*attractionDist);
        stroke(color(255));
        ellipse(0.5*width,0.5*height,2*limitDist,2*limitDist);
      }
    
    }
    
    
    class Hammer extends Flock{
      float headSize;
      PVector posHead, posBody, posMed, posTail, posEnd;
      float angHead, angBody, angMed, angTail;
    
      Hammer(PVector tempPos, PVector tempVel, color tempCol, float tempHeadSize){
        super(tempPos,tempVel,tempCol);
        headSize = tempHeadSize;
        posHead = pos.get();
        posBody = PVector.add(posHead, new PVector(0,2.1*headSize));
        posMed = PVector.add(posBody, new PVector(0,5.5*headSize));
        posTail = PVector.add(posMed, new PVector(0,2.2*headSize));   
        posEnd = PVector.add(posTail, new PVector(0,1.8*headSize));   
        angHead = 0;
        angBody = 0;
        angMed = 0;
        angTail = 0;
      }
     
      void update(){
        super.update();
    
        posHead = new PVector(pos.x,pos.y);
        angHead = atan2(vel.y,vel.x);
        if(isClose){
          angHead += 0.5*sin(0.4*frameCount);
          isClose = false;
        }
        angHead += 0.2*sin(0.2*frameCount);
    
        posBody = PVector.sub(posHead,new PVector(2.1*headSize*cos(angHead),2.1*headSize*sin(angHead)));
        angBody = atan2(posBody.y-posMed.y,posBody.x-posMed.x);
        
        posMed = PVector.sub(posBody, new PVector(5.5*headSize*cos(angBody),5.5*headSize*sin(angBody)));
        angMed = atan2(posMed.y-posTail.y,posMed.x-posTail.x);
        
        posTail = PVector.sub(posMed, new PVector(2.2*headSize*cos(angMed),2.2*headSize*sin(angMed)));
        angTail = atan2(posTail.y-posEnd.y,posTail.x-posEnd.x);
        posEnd = PVector.sub(posTail, new PVector(1.8*headSize*cos(angTail),1.8*headSize*sin(angTail)));
      }
    
      void paintDetail(){
        noStroke();
        fill(col);
        paintHead(posHead,angHead);
        paintBody(posBody,angBody);
        paintMed(posMed,angMed);
        paintTail(posTail,angTail);
      }
    
      void paintHead(PVector cen, float ang){
        pushMatrix();
          translate(cen.x,cen.y);
          rotate(HALF_PI + ang);
          beginShape();
            curveVertex(0,-0.5*headSize);
          
            curveVertex(1.1*headSize,-0.4*headSize);
            curveVertex(2.0*headSize,-0.3*headSize);
            curveVertex(2.3*headSize,-0.3*headSize);
            curveVertex(2.25*headSize,0.4*headSize);
            curveVertex(2.1*headSize,0.5*headSize);
            curveVertex(1.5*headSize,0.3*headSize);
            curveVertex(0.9*headSize,0.4*headSize);
            curveVertex(0.8*headSize,0.5*headSize);
            curveVertex(0.9*headSize,1.3*headSize);
            curveVertex(0.8*headSize,2.1*headSize);
            curveVertex(0.4*headSize,1.9*headSize);
           
            curveVertex(0,1.8*headSize);
          
            curveVertex(-0.4*headSize,1.9*headSize);
            curveVertex(-0.8*headSize,2.1*headSize);
            curveVertex(-0.9*headSize,1.3*headSize);
            curveVertex(-0.8*headSize,0.5*headSize);
            curveVertex(-0.9*headSize,0.4*headSize);
            curveVertex(-1.5*headSize,0.3*headSize);
            curveVertex(-2.1*headSize,0.5*headSize);
            curveVertex(-2.25*headSize,0.4*headSize);
            curveVertex(-2.3*headSize,-0.3*headSize);
            curveVertex(-2.0*headSize,-0.3*headSize);
            curveVertex(-1.1*headSize,-0.4*headSize);
          
            curveVertex(0,-0.5*headSize);
    
            curveVertex(1.1*headSize,-0.4*headSize);
            curveVertex(2.0*headSize,-0.3*headSize);
          endShape();
        popMatrix();
      }
    
      void paintBody(PVector cen, float ang){
        pushMatrix();
          translate(cen.x,cen.y);
          rotate(HALF_PI + ang);
          beginShape();
            curveVertex(0,-0.5*headSize);
          
            curveVertex(0.7*headSize,-0.2*headSize);
            curveVertex(0.9*headSize,0.0*headSize);
            curveVertex(1.1*headSize,0.3*headSize);
            curveVertex(2.4*headSize,0.7*headSize);
            curveVertex(3.3*headSize,1.1*headSize);
            curveVertex(3.1*headSize,1.1*headSize);
            curveVertex(1.5*headSize,1.1*headSize);
            curveVertex(1.0*headSize,1.3*headSize);
            curveVertex(0.9*headSize,1.1*headSize);
            curveVertex(0.85*headSize,2.8*headSize);
            curveVertex(0.95*headSize,3.2*headSize);
            curveVertex(1.2*headSize,3.55*headSize);
            curveVertex(1.5*headSize,4.0*headSize);
            curveVertex(1.1*headSize,3.95*headSize);
            curveVertex(0.9*headSize,3.95*headSize);
            curveVertex(0.7*headSize,4.1*headSize);
            curveVertex(0.4*headSize,5.3*headSize);
       
            curveVertex(0,5.2*headSize);
          
            curveVertex(-0.4*headSize,5.3*headSize);
            curveVertex(-0.7*headSize,4.1*headSize);
            curveVertex(-0.9*headSize,3.95*headSize);
            curveVertex(-1.1*headSize,3.95*headSize);
            curveVertex(-1.5*headSize,4.0*headSize);
            curveVertex(-1.2*headSize,3.55*headSize);
            curveVertex(-0.95*headSize,3.2*headSize);
            curveVertex(-0.85*headSize,2.8*headSize);
            curveVertex(-0.9*headSize,1.1*headSize);
            curveVertex(-1.0*headSize,1.3*headSize);
            curveVertex(-1.5*headSize,1.1*headSize);
            curveVertex(-3.1*headSize,1.1*headSize);
            curveVertex(-3.3*headSize,1.1*headSize);
            curveVertex(-2.4*headSize,0.7*headSize);
            curveVertex(-1.1*headSize,0.3*headSize);
            curveVertex(-0.9*headSize,0.0*headSize);
            curveVertex(-0.7*headSize,-0.2*headSize);
          
            curveVertex(0,-0.5*headSize);
    
            curveVertex(0.7*headSize,-0.2*headSize);
            curveVertex(0.9*headSize,0.0*headSize);
          endShape();
        popMatrix();
      }
    
      void paintMed(PVector cen, float ang){
        pushMatrix();
          translate(cen.x,cen.y);
          rotate(HALF_PI + ang);
          beginShape();
            curveVertex(0,-0.5*headSize);
          
            curveVertex(0.4*headSize,-0.1*headSize);
            curveVertex(0.2*headSize,1.8*headSize);
           
            curveVertex(0,2*headSize);
          
            curveVertex(-0.2*headSize,1.8*headSize);
            curveVertex(-0.4*headSize,-0.1*headSize);
          
            curveVertex(0,-0.5*headSize);
    
            curveVertex(0.4*headSize,-0.1*headSize);
            curveVertex(0.2*headSize,1.8*headSize);
          endShape();
        popMatrix();
      }
    
      void paintTail(PVector cen, float ang){
        pushMatrix();
          translate(cen.x,cen.y);
          rotate(HALF_PI + ang);
          beginShape();
            curveVertex(0,-0.5*headSize);
          
            curveVertex(0.2*headSize,-0.05*headSize);
           
            curveVertex(0,2.8*headSize);
          
            curveVertex(-0.2*headSize,-0.05*headSize);
          
            curveVertex(0,-0.5*headSize);
    
            curveVertex(0.2*headSize,-0.05*headSize);
            curveVertex(0,2.8*headSize);
          endShape();
        popMatrix();
      }
    
    }
    
    
    class Jellyfish extends Flock{
      float headSize;
      int nArms;
      float lengthArms;
      Arm[] arms;
      float ang;
    
      Jellyfish(PVector tempPos, PVector tempVel, color tempCol, float tempHeadSize, int tempNArms, int tempLengthArms){
        super(tempPos,tempVel,tempCol);
        headSize = tempHeadSize;
        nArms = tempNArms;
        lengthArms = tempLengthArms;
        arms = new Arm[nArms];
        for(int i = 0; i < nArms; i++){
          float offset = 0;
          if(nArms > 1){
            offset = -0.3*headSize + 0.6*headSize*i/(nArms-1);
          }
          int armSize = int(random(0.7*lengthArms,lengthArms));
          arms[i] = new Arm(offset,armSize,col);
        }
        ang = 0;
      }
    
      void update(){
        super.update();
        
        ang = atan2(vel.y,vel.x);
        for(int i = 0; i < nArms; i++){
          arms[i].update(pos,ang);
        }
        /* 
        if(isClose){
          float r = red(col);
          float g = green(col);
          float b = blue(col);
          float a = alpha(col);
          r += 10;
          b -= 10;
          col = color(r,g,b,a);
          for(int i = 0; i < nArms; i++){
            arms[i].changeColor(col);
          }
          isClose = false;
        }
        */
      }
      
      void paintDetail(){
        paintHead(pos,ang,col); 
        for(int i = 0; i < nArms; i++){
          arms[i].paint();
        }    
      }
      
      void paintHead(PVector cen, float ang, color c){
        noStroke();
        fill(c);
        pushMatrix();
          translate(cen.x,cen.y);
          rotate(HALF_PI + ang);
          beginShape();
            curveVertex(-headSize,0);
            
            curveVertex(0,-0.7*headSize);
            
            curveVertex(headSize,0);
            
            curveVertex(0,0.3*headSize);
            
            curveVertex(-headSize,0);
            
            curveVertex(0,-0.7*headSize);
            curveVertex(headSize,0);
          endShape();
        popMatrix();
      }
    }
    
    
    class Arm{
      PVector topLink;
      float offset;
      int nLinks;
      Link[] links;
      color col;
            
      Arm(float tempOffset, int tempNLinks, color tempCol){
        topLink = new PVector(0,0,0);
        offset = tempOffset;
        nLinks = tempNLinks;
        links = new Link[nLinks];
        col = tempCol;
    
        for(int i = 0; i < nLinks; i++){
          float sep = (nLinks-i) + 5;
          float diam = ((nLinks-i) + 2)/1.4;
          links[i] = new Link(sep,diam,col);
        }
      }
      
      void update(PVector newPos, float ang){
        topLink = PVector.add(newPos,new PVector(offset*cos(HALF_PI + ang),offset*sin(HALF_PI + ang)));
        links[0].update(topLink);
        for(int i = 1; i < nLinks; i++){
          links[i].update(links[i-1].pos);
        }
      }
    
      void paint(){
        links[0].paint(topLink);
        for(int i = 1; i < nLinks; i++){
          links[i].paint(links[i-1].pos);
        }
      }
      
      void changeColor(color c){
        for(int i = 0; i < nLinks; i++){
          links[i].col = c;
        }
      }
    }
    
    
    class Link{
      PVector pos;
      float sep;
      float diam;
      color col;
        
      Link(float tempSep, float tempDiam, color tempCol){
        pos = new PVector(0,0,0);
        sep = tempSep;
        diam = tempDiam;
        col = tempCol;
      }
    
      void update(PVector prev){
        float ang = atan2(prev.y-pos.y,prev.x-pos.x);
        pos.x = prev.x - sep*cos(ang);
        pos.y = prev.y - sep*sin(ang);
      }
      
      void paint(PVector prev){
        stroke(col);
        strokeWeight(diam);
        line(prev.x,prev.y,pos.x,pos.y);
      }
    }  
    
    
    import controlP5.*;
    
    public ControlP5 cp5;
    public int nFishes = 300;
    public int nJellys = 100;
    public int nWhales = 1;
    public int nHammers = 3;
    public float repulsionDist = 30; 
    public float alignDist = 50; 
    public float attractionDist = 150; 
    public float huntDist = 200; 
    public float limitDist = 300; 
    public float repulsionDistSqr = sq(repulsionDist); 
    public float alignDistSqr = sq(alignDist); 
    public float attractionDistSqr = sq(attractionDist); 
    public float huntDistSqr = sq(huntDist); 
    public float limitDistSqr = sq(limitDist); 
    public float maxVel = 5; 
    public boolean paintLines = false; 
    public boolean paintLimits = false;
    public boolean paintDetails = true;
    
    ArrayList fishes = new ArrayList(nFishes);
    ArrayList jellys = new ArrayList(nJellys);
    ArrayList whales = new ArrayList(nWhales);
    ArrayList hammers = new ArrayList(nHammers);
    
    PImage bgImg;
    
    void setup(){
      size(900,800);
      smooth();
    
      // Fishes
      for(int i = 0; i < nFishes; i++){
        float posAngle = random(0,TWO_PI);
        float posMagnitude = random(0,limitDist);
        PVector pos = new PVector(0.5*width+posMagnitude*cos(posAngle),0.5*height+posMagnitude*sin(posAngle));
        float velAngle = random(0,TWO_PI);
        float velMagnitude = 1;
        PVector vel = new PVector(velMagnitude*cos(velAngle),velMagnitude*sin(velAngle));
        color col = color(50,50,155);
        float headSize = 7;
        Fish f = new Fish(pos,vel,col,headSize);
        fishes.add(f);
      }
      
      // Jellyfishes
      for(int i = 0; i < nJellys; i++){
        float posAngle = random(0,TWO_PI);
        float posMagnitude = random(0,limitDist);
        PVector pos = new PVector(0.5*width+posMagnitude*cos(posAngle),0.5*height+posMagnitude*sin(posAngle));
        float velAngle = random(0,TWO_PI);
        float velMagnitude = 1;
        PVector vel = new PVector(velMagnitude*cos(velAngle),velMagnitude*sin(velAngle));
        color col = color(200,200,230,150);
        float headSize = random(8,11);
        int nArms = 4;
        int lengthArms = int(random(headSize*0.5,headSize*0.6));
        Jellyfish j = new Jellyfish(pos,vel,col,headSize,nArms,lengthArms);
        jellys.add(j);
      }
      
      // Killer whales
      for(int i = 0; i < nWhales; i++){
        float posAngle = random(0,TWO_PI);
        float posMagnitude = random(0,limitDist);
        PVector pos = new PVector(0.5*width+posMagnitude*cos(posAngle),0.5*height+posMagnitude*sin(posAngle));
        float velAngle = random(0,TWO_PI);
        float velMagnitude = 0;
        PVector vel = new PVector(velMagnitude*cos(velAngle),velMagnitude*sin(velAngle));
        color col = color(0);
        float headSize = random(8,11);
        Whale w = new Whale(pos,vel,col,headSize);
        whales.add(w);
      }
    
      // Hammer sharks
      for(int i = 0; i < nHammers; i++){
        float posAngle = random(0,TWO_PI);
        float posMagnitude = random(0,limitDist);
        PVector pos = new PVector(0.5*width+posMagnitude*cos(posAngle),0.5*height+posMagnitude*sin(posAngle));
        float velAngle = random(0,TWO_PI);
        float velMagnitude = 0;
        PVector vel = new PVector(velMagnitude*cos(velAngle),velMagnitude*sin(velAngle));
        color col = color(100,100,100);
        float headSize = random(5,6);
        Hammer h = new Hammer(pos,vel,col,headSize);
        hammers.add(h);
      }
      
      // Circular pool
      bgImg = water();
    
      // ControlP5 controls
      controlPanel();
    }
    
    void draw(){
      background(bgImg);
      
      // Fishes    
      for(int i = 0; i < nFishes; i++){
        Fish f = (Fish) fishes.get(i);
        f.update();
        if(paintDetails){
          f.paintDetail();
        }
        else{
          f.paint();
        }
        if(paintLimits && i == 0){
          f.paintLimits();
        }
      }
      for(int i = 0; i < nFishes; i++){
        Fish f = (Fish) fishes.get(i);
        f.evaluateInteractions(fishes,nFishes,true,true,true,false,false);
        f.evaluateInteractions(whales,nWhales,false,false,false,true,false);
        f.evaluateInteractions(hammers,nHammers,false,false,false,true,false);
        f.keepClose();
      }
      
      // Jellyfishes
      for(int i = 0; i < nJellys; i++){
        Jellyfish j = (Jellyfish) jellys.get(i);
        j.update();
        if(paintDetails){
          j.paintDetail();
        }
        else{
          j.paint();
        }
      }
      for(int i = 0; i < nJellys; i++){
        Jellyfish j = (Jellyfish) jellys.get(i);
        j.evaluateInteractions(jellys,nJellys,true,true,true,false,false);
        j.evaluateInteractions(whales,nWhales,false,false,false,true,false);
        j.evaluateInteractions(hammers,nHammers,false,false,false,true,false);
        j.keepClose();
      }
    
      // Killer whales
      for(int i = 0; i < nWhales; i++){
        Whale w = (Whale) whales.get(i);
        w.update();
        if(paintDetails){
          w.paintDetail();
        }
        else{
          w.paint();
        }
      }
      for(int i = 0; i < nWhales; i++){
        Whale w = (Whale) whales.get(i);
        w.evaluateInteractions(whales,nWhales,true,false,false,false,false);
        w.evaluateInteractions(fishes,nFishes,false,false,false,false,true);
        w.evaluateInteractions(jellys,nJellys,false,false,false,false,true);
        w.evaluateInteractions(hammers,nHammers,true,false,false,false,false);
        w.keepClose();
      }
      
      // Hammer sharks 
      for(int i = 0; i < nHammers; i++){
        Hammer h = (Hammer) hammers.get(i);
        h.update();
        if(paintDetails){
          h.paintDetail();
        }
        else{
          h.paint();
        }
      }
      for(int i = 0; i < nHammers; i++){
        Hammer h = (Hammer) hammers.get(i);
        h.evaluateInteractions(hammers,nHammers,true,true,true,false,false);
        h.evaluateInteractions(fishes,nFishes,false,false,false,false,true);
        h.evaluateInteractions(jellys,nJellys,false,false,false,false,true);
        h.evaluateInteractions(whales,nWhales,true,false,false,false,false);
        h.keepClose();
      }
    
    }
    
    
    
    PImage water(){
      PImage img = createImage(width,height,RGB);
    
      for (int y = 0; y < height; y++){
        for (int x = 0; x < width; x++){
          int loc = x + y*width;
          float rad = sqrt(sq(x-0.5*width) + sq(y-0.5*height));
          float ang = abs(atan2(y-0.5*height,x-0.5*width));
          float g = 15*noise(ang,0.01*rad) + 0.07*rad + 0;
          float b = 20*noise(ang,0.03*rad) + 0.07*rad + 20;
          float rand = random(3+0.04*rad);
          img.pixels[loc] = color(rand,rand+g,rand+b);
        }
      }
      
      return img;
    }
    
    
    class Whale extends Flock{
      float headSize;
      PVector posHead, posBody, posMed, posTail, posEnd;
      float angHead, angBody, angMed, angTail;
    
      Whale(PVector tempPos, PVector tempVel, color tempCol, float tempHeadSize){
        super(tempPos,tempVel,tempCol);
        headSize = tempHeadSize;
        posHead = pos.get();
        posBody = PVector.add(posHead, new PVector(0,0.6*headSize));
        posMed = PVector.add(posBody, new PVector(0,4.5*headSize));
        posTail = PVector.add(posMed, new PVector(0,2.4*headSize));   
        posEnd = PVector.add(posTail, new PVector(0,1.8*headSize));   
        angHead = 0;
        angBody = 0;
        angMed = 0;
        angTail = 0;
      }
     
      void update(){
        super.update();
    
        posHead = new PVector(pos.x,pos.y);
        angHead = atan2(vel.y,vel.x);
        if(isClose){
          angHead += 0.5*sin(0.4*frameCount);
          isClose = false;
        }
        
        posBody = PVector.sub(posHead,new PVector(0.6*headSize*cos(angHead),0.6*headSize*sin(angHead)));
        angBody = atan2(posBody.y-posMed.y,posBody.x-posMed.x);
        
        posMed = PVector.sub(posBody, new PVector(4.5*headSize*cos(angBody),4.5*headSize*sin(angBody)));
        angMed = atan2(posMed.y-posTail.y,posMed.x-posTail.x);
        
        posTail = PVector.sub(posMed, new PVector(2.4*headSize*cos(angMed),2.4*headSize*sin(angMed)));
        angTail = atan2(posTail.y-posEnd.y,posTail.x-posEnd.x);
        
        posEnd = PVector.sub(posTail, new PVector(1.8*headSize*cos(angTail),1.8*headSize*sin(angTail)));
      }
    
      void paintDetail(){
        noStroke();
        paintHead(posHead,angHead,col);
        paintBody(posBody,angBody,col);
        paintMed(posMed,angMed,col);
        paintTail(posTail,angTail,col);
      }
    
      void paintHead(PVector cen, float ang, color c){
        fill(c);
        pushMatrix();
          translate(cen.x,cen.y);
          rotate(HALF_PI + ang);
          beginShape();
            curveVertex(0,-1.5*headSize);
          
            curveVertex(0.4*headSize,-1.1*headSize);
            curveVertex(0.85*headSize,-0.3*headSize);
            curveVertex(1.0*headSize,0.6*headSize);
            curveVertex(0.6*headSize,0.5*headSize);
           
            curveVertex(0,0.2*headSize);
          
            curveVertex(-0.6*headSize,0.5*headSize);
            curveVertex(-1.0*headSize,0.6*headSize);
            curveVertex(-0.85*headSize,-0.3*headSize);
            curveVertex(-0.4*headSize,-1.1*headSize);
          
            curveVertex(0,-1.5*headSize);
    
            curveVertex(0.4*headSize,-1.1*headSize);
            curveVertex(0.85*headSize,-0.3*headSize);
          endShape();
          fill(255,150);
          beginShape();
            curveVertex(0.4*headSize,-0.7*headSize);
            curveVertex(0.65*headSize,-0.4*headSize);
            curveVertex(0.85*headSize,0.2*headSize);
            curveVertex(0.6*headSize,-0.1*headSize);
            curveVertex(0.5*headSize,-0.4*headSize);
            curveVertex(0.4*headSize,-0.7*headSize);
            curveVertex(0.65*headSize,-0.4*headSize);
          endShape();
          beginShape();
            curveVertex(-0.4*headSize,-0.7*headSize);
            curveVertex(-0.65*headSize,-0.4*headSize);
            curveVertex(-0.85*headSize,0.2*headSize);
            curveVertex(-0.6*headSize,-0.1*headSize);
            curveVertex(-0.5*headSize,-0.4*headSize);
            curveVertex(-0.4*headSize,-0.7*headSize);
            curveVertex(-0.65*headSize,-0.4*headSize);
          endShape();
        popMatrix();
      }
    
      void paintBody(PVector cen, float ang, color c){
        fill(c);
        pushMatrix();
          translate(cen.x,cen.y);
          rotate(HALF_PI + ang);
          beginShape();
            curveVertex(0,-0.5*headSize);
          
            curveVertex(0.9*headSize,-0.2*headSize);
            curveVertex(1.05*headSize,0.2*headSize);
            curveVertex(1.25*headSize,0.3*headSize);
            curveVertex(1.85*headSize,0.7*headSize);
            curveVertex(2.2*headSize,1.3*headSize);
            curveVertex(2.1*headSize,1.9*headSize);
            curveVertex(1.7*headSize,2.1*headSize);
            curveVertex(1.2*headSize,2.0*headSize);
            curveVertex(1.1*headSize,2.0*headSize);
            curveVertex(0.85*headSize,4.4*headSize);
           
            curveVertex(0,4.2*headSize);
          
            curveVertex(-0.85*headSize,4.4*headSize);
            curveVertex(-1.1*headSize,2.0*headSize);
            curveVertex(-1.2*headSize,2.0*headSize);
            curveVertex(-1.7*headSize,2.1*headSize);
            curveVertex(-2.1*headSize,1.9*headSize);
            curveVertex(-2.2*headSize,1.3*headSize);
            curveVertex(-1.85*headSize,0.7*headSize);
            curveVertex(-1.25*headSize,0.3*headSize);
            curveVertex(-1.05*headSize,0.2*headSize);
            curveVertex(-0.9*headSize,-0.2*headSize);
          
            curveVertex(0,-0.5*headSize);
    
            curveVertex(0.9*headSize,-0.2*headSize);
            curveVertex(1.05*headSize,0.2*headSize);
          endShape();
          fill(255,150);
          beginShape();
            curveVertex(0.6*headSize,2.7*headSize);
            curveVertex(0.9*headSize,3.6*headSize);
            curveVertex(0.8*headSize,4.1*headSize);
            curveVertex(0.6*headSize,3.8*headSize);
            curveVertex(0.4*headSize,3.3*headSize);
            curveVertex(0.6*headSize,2.7*headSize);
            curveVertex(0.9*headSize,3.6*headSize);
          endShape();
          beginShape();
            curveVertex(-0.6*headSize,2.7*headSize);
            curveVertex(-0.9*headSize,3.6*headSize);
            curveVertex(-0.8*headSize,4.1*headSize);
            curveVertex(-0.6*headSize,3.8*headSize);
            curveVertex(-0.4*headSize,3.3*headSize);
            curveVertex(-0.6*headSize,2.7*headSize);
            curveVertex(-0.9*headSize,3.6*headSize);
          endShape();
        popMatrix();
      }
    
      void paintMed(PVector cen, float ang, color c){
        fill(c);
        pushMatrix();
          translate(cen.x,cen.y);
          rotate(HALF_PI + ang);
          beginShape();
            curveVertex(0,-0.5*headSize);
          
            curveVertex(0.8*headSize,-0.1*headSize);
            curveVertex(0.6*headSize,1.2*headSize);
            curveVertex(0.3*headSize,2.2*headSize);
           
            curveVertex(0,2.1*headSize);
          
            curveVertex(-0.3*headSize,2.2*headSize);
            curveVertex(-0.6*headSize,1.2*headSize);
            curveVertex(-0.8*headSize,-0.1*headSize);
          
            curveVertex(0,-0.5*headSize);
    
            curveVertex(0.8*headSize,-0.1*headSize);
            curveVertex(0.6*headSize,1.2*headSize);
          endShape();
        popMatrix();
      }
    
      void paintTail(PVector cen, float ang, color c){
        fill(c);
        pushMatrix();
          translate(cen.x,cen.y);
          rotate(HALF_PI + ang);
          beginShape();
            curveVertex(0,-0.5*headSize);
          
            curveVertex(0.25*headSize,-0.2*headSize);
            curveVertex(0.3*headSize,0.6*headSize);
            curveVertex(1.3*headSize,1.2*headSize);
            curveVertex(1.6*headSize,1.8*headSize);
            curveVertex(1.2*headSize,1.7*headSize);
            curveVertex(0.3*headSize,1.7*headSize);
            curveVertex(0.0*headSize,1.55*headSize);
           
            curveVertex(0,1.5*headSize);
          
            curveVertex(-0.0*headSize,1.55*headSize);
            curveVertex(-0.3*headSize,1.7*headSize);
            curveVertex(-1.2*headSize,1.7*headSize);
            curveVertex(-1.6*headSize,1.8*headSize);
            curveVertex(-1.3*headSize,1.2*headSize);
            curveVertex(-0.3*headSize,0.6*headSize);
            curveVertex(-0.25*headSize,-0.2*headSize);
          
            curveVertex(0,-0.5*headSize);
    
            curveVertex(0.25*headSize,-0.2*headSize);
            curveVertex(0.3*headSize,0.6*headSize);
          endShape();
        popMatrix();
      }
    
    }
    
    

    code

    tweaks (0)

    about this sketch

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

    license

    advertisement

    Javier Graciá Carpio

    Sea life

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

    My first flocking experiment.

    Everything started from this flocking tutorial:
    http://www.flight404.com/blog/?p=459
    http://libcinder.org/docs/dev/flocking_chapter1.html

    Click on the screen to make the controls appear.

    ale plus+
    30 Aug 2012
    Better than Planet Earth documentaries!
    Gracias Ale! At least easier to film ;)
    Davie Khonje
    6 Jan 2013
    this really amazing i like what you have done
    Thanks Davie!
    John E.
    18 Aug 2013
    Very cool
    fred
    8 Nov 2013
    superbe, really nice
    You need to login/register to comment.