> show canvas only <


/* built with Studio Sketchpad: 
 *   https://sketchpad.cc
 * 
 * observe the evolution of this sketch: 
 *   https://studio.sketchpad.cc/sp/pad/view/ro.Oj39fnDIoU4/rev.574
 * 
 * authors: 
 *   Wolfe

 * license (unless otherwise specified): 
 *   creative commons attribution-share alike 3.0 license.
 *   https://creativecommons.org/licenses/by-sa/3.0/ 
 */ 



// My older sketch Wolves and Sheeps
// Wolves pursue sheeps, sheeps evade wolves
// Each tries not to collide others (of their kind) 
// Pursuing wolves and evading sheeps have red circle around them
// Roaming ones are without these 

// May 9-th 2012 - lame flocking

// my first attempt to use vectors at all
ArrayList Pack, Herd;
PVector average;
int count;
 
int WOLVES = 10;
int SHEEPS = 100;
int wIndentDIST = 15;
int sIndentDIST = 15;

int sFlockDIST = 100;
 
////// main setup ////////////////
void setup() {
  size(600, 600, P2D);
  Pack = new ArrayList();
  Herd = new ArrayList();
  

  for (int  w=1; w<=WOLVES; w++) {
    Pack.add(new Wolf());
  }
 
  for (int  s=1; s<=SHEEPS; s++) {
    Herd.add(new Sheep());
  }
}
 
////// main draw ////////////
 
void draw() {
  background(#02A713); // green lawn
 
  /////////////////////// RESETING ////////////////////////
  for (int  w=0; w<Pack.size(); w++) {
    Wolf wolf = (Wolf) Pack.get(w);
    wolf.pursuedTarget = null;
    wolf.pursuing = false;
    //    wolf.maxSpeed = 2;
  }
 
  for (int  s=0; s<Herd.size(); s++) {
    Sheep sheep = (Sheep) Herd.get(s);
    sheep.evading = false;
    sheep.flock = false;
    //  sheep.maxSpeed = 5;
  }
  /////////////////////////////////////////////////////////
 
  ////////// indenting ///////////
 
  for (int  w1=0; w1<Pack.size(); w1++) {
    Wolf wolf1 = (Wolf) Pack.get(w1);
    for (int  w2=0; w2<Pack.size(); w2++) {
      Wolf wolf2 = (Wolf) Pack.get(w2);
      if (w1 != w2) {
        float dist = wolf1.pos.dist(wolf2.pos);
        if (dist < wIndentDIST) {
          wolf1.evade(PVector.sub(wolf2.pos, wolf1.pos));
        }
      }
    }
  }
 
  count = 0;
  average = new PVector(0, 0);
 
  for (int  s1=0; s1<Herd.size(); s1++) {
    Sheep sheep1 = (Sheep) Herd.get(s1);
    for (int  s2=0; s2<Herd.size(); s2++) {
      Sheep sheep2 = (Sheep) Herd.get(s2);
      if (s1 != s2) {
 
        float dist = sheep1.pos.dist(sheep2.pos);
 
        if (dist < sIndentDIST) {
          sheep1.evade(PVector.sub(sheep2.pos, sheep1.pos));
        }

//////////////////!!!!!!!!!!!!!!!!!!!!!   flocking trying    
        if (dist < sFlockDIST) {
            PVector averageDir = PVector.add(sheep1.pos,sheep2.pos);
            averageDir.div(2);
            averageDir.normalize();


          sheep1.pursue(averageDir);
          sheep2.pursue(averageDir);

        }
//////////////////!!!!!!!!!!!!!!!!!!!!!        
        
        
      }
    }
  }
 
 
  ////////////////////////////////
 
  ////////////////// MAIN STEERING ENGINE //////////////////
  for (int  w=0; w<Pack.size(); w++) {
    Wolf wolf = (Wolf) Pack.get(w);
 
    //
    for (int  s=0; s<Herd.size(); s++) {
      Sheep sheep = (Sheep) Herd.get(s);
 
      if (sheep.pos.dist(wolf.pos) < sheep.fleeDist) {
        sheep.evade(PVector.sub(wolf.pos, sheep.pos));
        sheep.evading = true;
      }
 
      if (wolf.pos.dist(sheep.pos) < wolf.attackDist) {
        wolf.pursuing = true;
        if (wolf.pursuedTarget == null) wolf.pursuedTarget = sheep;
 
        //        if (wolf.pos.dist(sheep.pos) < 5) Herd.remove(s); // kill
 
        if (wolf.pos.dist(sheep.pos) < wolf.pos.dist(wolf.pursuedTarget.pos)) {
          wolf.pursuedTarget = sheep;
        }
 
        sheep.evade(PVector.sub(wolf.pos, sheep.pos));
        sheep.evading = true;
       //         sheep.maxSpeed = 5;
      }    else sheep.wander();
//      }    else sheep.pursue(new PVector(10,10));
 
      //
    }
    //
 
    if (wolf.pursuedTarget != null) {
      wolf.pursue(PVector.sub(wolf.pursuedTarget.pos, wolf.pos));
      wolf.pursuing = true;
      //    wolf.maxSpeed = 5;
    }
    else wolf.wander();
  }
  ////////////////////////////////////////////////////////// 
 
  for (int  w=0; w<Pack.size(); w++) {
    Wolf wolf = (Wolf) Pack.get(w);
    wolf.update();
    wolf.draw();
  }
 
  for (int  s=0; s<Herd.size(); s++) {
    Sheep sheep = (Sheep) Herd.get(s);
    sheep.update();
    sheep.draw();
  }
}
///////////////////////////////

///////////////////////////////////////
///////////////////////////////////////

//////////////// Animal //////////////
class  Animal {
  public PVector pos, vel, acc;
  public PVector vecAcc, vecVel;
  int radius;
  float maxSpeed;
  float friction;
 
  Animal() {
    vel = new PVector(0, 0);
    acc = new PVector(0, 0);
 
    vecAcc = new PVector(0, 0);
    vecVel = new PVector(0, 0);
 
    radius = 5;
    maxSpeed = 5;
    friction =  0.05;
  }
 
 
  void drawVector(PVector v, PVector loc, float scal) {
      pushStyle();
    float len = v.mag()*scal;
    stroke(0,100);
    line(loc.x, loc.y, loc.x+v.x*scal, loc.y+v.y*scal);
    popStyle();
  }
 
  public void pursue(PVector target) {
    acc.add(target);
  }
  public void evade(PVector target) {
    acc.sub(target);
  }
 
  public void wander() {
    if (abs(vel.x) < abs(vel.y)) pursue(new PVector(random(-10, 10), 0));
    else pursue(new PVector(0, random(-10, 10)));
  }
 
  public void update() {
 
    vecAcc.set(acc);
    acc.normalize();
 
    vel.add(acc);
 
    //    vel.x += vel.x * -friction;
    //    vel.y += vel.y * -friction;
 
    vecVel.set(vel);
    vel.limit(maxSpeed);
 
    pos.add(vel);
    acc.set(0, 0, 0);
 
    //    acc.set(0,0,0);  //brzda
 
    ////// BOUNCE //////////
    //if ((pos.x+radius>width)  || (pos.x-radius<0)) vel.x *= -1;
    //if ((pos.y+radius>height) || (pos.y-radius<0)) vel.y *= -1;
    ////// BOUNCE //////////
 
    ////// SEAMLESS //////
    if (pos.x>width)  pos.x = 0;
    if (pos.x<0)      pos.x = width;
    if (pos.y>height) pos.y = 0;
    if (pos.y<0)      pos.y = height;
    ////// SEAMLESS //////
  }
}

///////////////////////////////////////
///////////////////////////////////////

///////////// Sheep /////////////
class Sheep extends Animal {
  boolean evading, seekingFood, flock;
  int fleeDist = 50;
  int feedDist = 200;
 
 
  Sheep() {
    pos = new PVector(random(20, width-20), random(20, height-20));
    evading = false;
  }
 
  Sheep(float x, float y) {
    pos = new PVector(x, y);
    evading = false;
  }
 
  public void draw() {
 
    pushStyle();
    stroke(0);
    if (evading) {
      strokeWeight(2);
      stroke(255, 0, 0);
    }
    //    elseif (seekingFood) stroke(0, 255, 0);
    else {
      strokeWeight(1);
      stroke(0);
    }
 
    fill(255);
    ellipse(pos.x, pos.y, radius*2, radius*2);
    popStyle();
 
 
    pushStyle();
    strokeWeight(1);
    drawVector(vel, pos, 4);
    popStyle();
 
 
 
    /*
       pushStyle();
     stroke(255, 100, 100, 200);
     strokeWeight(3);
     drawVector(acc, pos, 25 );
     popStyle();
     */
  }
}


///////////////////////////////////////
///////////////////////////////////////

///////////// Wolf ////////////////
 
class Wolf extends Animal {
  boolean pursuing;
  Sheep pursuedTarget;
  int attackDist = 50;
 
  Wolf() {
    pos = new PVector(random(20, width-20), random(20, height-20));
    pursuing = false;
  }
 
  Wolf(float x, float y) {
    pos = new PVector(x, y);
    pursuing = false;
  }
 
  public void draw() {
 
    pushStyle();
    if (pursuing) {
      strokeWeight(2);
      stroke(255, 0, 0);
    }
    else {
      strokeWeight(1);
      stroke(0);
    }
    fill(0);
    ellipse(pos.x, pos.y, radius*2, radius*2);
    popStyle();
 
 
    pushStyle();
    strokeWeight(1);
    drawVector(vel, pos, 4);
    popStyle();
 
    /*
       pushStyle();
     stroke(255, 100, 100, 200);
     strokeWeight(3);
     drawVector(acc, pos, 25 );
     popStyle();
     */
  }
}