> show canvas only <


/* built with Studio Sketchpad: 
 *   https://sketchpad.cc
 * 
 * observe the evolution of this sketch: 
 *   https://studio.sketchpad.cc/sp/pad/view/ro.AK9M$BLEBLj/rev.9
 * 
 * authors: 
 *   GoToLoop

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



/**
 * Anthills (v2.1)
 * by  ArnaudM (2014/Nov/30)
 * mod GoToLoop
 *
 * forum.processing.org/two/discussion/8380/
 * issues-with-my-anthill-program
 *
 * studio.processingtogether.com/sp/pad/export/ro.91A3Jfnrsldhp/latest
 */

// Sketch's Global Constants:
static final int COLONIES = 5, ANTS = 20, FPS = 60;

// Sketch's Global Variables:
final Anthill[] anthills = new Anthill[COLONIES];
boolean isLooping = true;

// Sketch's User Function:
void instantiateAnthills(int ants) {
  for (int i = 0; i != COLONIES; anthills[i++] = new Anthill(ants));
}

// Sketch's Callback Functions:
void setup() {
  size(1280, 800, JAVA2D);

  ellipseMode(CENTER);
  frameRate(FPS);
  smooth(4);
  noStroke();

  instantiateAnthills(ANTS);
}

void draw() {
  background(0);
  for (Anthill hill : anthills)  hill.action();
}

void keyTyped() {
  if (isLooping ^= true)  loop();
  else                  noLoop();
}

void mousePressed() {
  if (mouseButton == LEFT)  keyTyped();
  else       instantiateAnthills(ANTS);
}

final class Anthill {
  // Class Anthill's Constants:
  static final int REGION = 30, FRONTIER = 4*REGION;

  // Class Anthill's Instance Variables:
  final color colour = (int) random(#000000);
  final PVector pos;
  final Ant[] ants;

  // Class Anthill's Constructor:
  Anthill(int qty) {
    ants = new Ant[qty];

    int offset  = REGION + Ant.DIAM;
    int centerX = (int) random(offset, width  - offset);
    int centerY = (int) random(offset, height - offset);
    pos = new PVector(centerX, centerY);

    for (int i = 0; i != qty; ++i) {
      float posX = centerX + random(-REGION, REGION);
      float posY = centerY + random(-REGION, REGION);
      ants[i] = new Ant(posX, posY);
    }
  }

  // Class Anthill's Method:
  void action() {
    fill(colour);
    for (Ant a : ants)  a.action(pos);
  }
}

final class Ant {
  // Class Ant's Constants:
  static final int DIAM = 10, FPS = 60; // FPS needed here in JS Mode!
  static final float MAX_VEL = 2.0;
  static final int MIN_FRAMES = FPS>>1, MAX_FRAMES = 4*FPS;

  // Class Ant's Instance Variables:
  final PVector pos, vel = new PVector();
  int targetFrame = frameCount;

  // Class Ant's Constructor:
  Ant(float x, float y) {
    pos = new PVector(x, y);
  }

  // Class Ant's Methods:
  void action(PVector center) {
    if (frameCount >= targetFrame)  redefine(center);
    update();
    display();
  }

  void display() {
    ellipse(pos.x, pos.y, DIAM, DIAM);
  }

  void update() {
    pos.add(vel);
  }

  void redefine(PVector hill) {
    float dx = random(-Anthill.FRONTIER, Anthill.FRONTIER);
    float dy = random(-Anthill.FRONTIER, Anthill.FRONTIER);
    float sp = random(MAX_VEL);

    vel.set(hill);
    vel.add(dx, dy, 0);
    vel.sub(pos);
    vel.normalize(); // setMag() not available in PJS v1.4.1.
    vel.mult(sp);

    int tf = round(random(MIN_FRAMES, MAX_FRAMES)/MAX_VEL);
    targetFrame = frameCount + tf;
  }
}