Red Fish Blue Fish

A bunch of particles moving with Perlin noise, a type of algorithm that returns 'smooth' random numbers in order to get that fish like movement from the particles. Perlin noise is prevalent in a lot of generative art because it looks much better than true randomness from a design point of view. Click on the canvas to add more particles! Beware, if you add too many, it might start to slow down.

Reset using the R key on your keyboard. Pause the piece at any time using the S key on your keyboard.

var particles = [];

var xoff_ = 200;

var inc = .0004; // .0004

let looping = true;

// Setup function
function setup() {
  var canvas = createCanvas(500, 500);
  canvas.parent('sketch-holder');
  resetSketch();
}

function resetSketch() {
  particles = [];
  for (var i =0; i < 20; i++){
    particles.push(new Particle(mouseX, mouseY));
  }
}
// Adds new particle when mouse is clicked
function mousePressed() {
  if (mouseX <= width && mouseX >= 0
&& mouseY >= 0 && mouseY <= height) {
  particles.push(new Particle(mouseX, mouseY));
  }
}

// Draws particles using for loop
function draw() {
  var back_col = map(noise(xoff_), 0, 1, 0 , 200);
  background(255);
  xoff_ += inc;

for (var i = 0; i < particles.length; i++) {
   particles[i].update();
   particles[i].show();
}
}

// Class of particles, includes update and show functions
class Particle {
  constructor(x,y) {
  this.pos = createVector(x, y);
  this.ranCol = random(3);

  this.history = [];
  this.xoff = random(10000);
  this.yoff = random(20000);
  this.vel = p5.Vector.random2D();

  this.follow_mode = false;

}
  // Didn't use this function
  switch() {
  if (!this.follow_mode) {
    this.follow_mode = true;
  } else {
    this.follow_mode = false;
  }
  }

  // Didn't use this function
  applyForce(force) {
    this.acc.add(force);
  }

  // Updates the position of particle
  update() {
    this.vel = createVector(map(noise(this.xoff),0,1, 0, width), map(noise(this.yoff), 0, 1, 0, height));
    this.pos.add(this.vel);

    this.pos.x = map(noise(this.xoff),0,1, 0, width);
    this.pos.y = map(noise(this.yoff), 0, 1, 0, height);
    this.xoff += .007;
    this.yoff += .007;

    var v = createVector(this.pos.x, this.pos.y);

    this.history.push(v);

    if (this.history.length > 25) { //35 normally
      this.history.splice(0, 1);
    }


  }

  show() {
    // makes nice circle when they first show up
    stroke(0);
    fill(0, 100);
    ellipse(this.pos.x, this.pos.y, 24, 24);

    for (var i = 0; i < this.history.length;i++) {
      this.col = 80;
      this.col1 = 80;
      this.col2 = 80;
      noStroke();
      colorMode(RGB);
      if (this.ranCol < 1) {
        fill(this.col, 0, 0, 150);
      } else if (1 < this.ranCol < 2) {
        fill(0, this.col2, this.col1, 150);
      } else {
        fill(0, 100);
      }
      var pos_his = this.history[i];
      ellipse(pos_his.x, pos_his.y, i+2, i+2);
    }
  }
}