final int NB_CILIUM = 12;
final float CELL_RAD = 13;
Cilium[] tabCilium = new Cilium[NB_CILIUM];
float R, G, B, Rspeed, Gspeed, Bspeed, mouseSpeed;
ArrayList<Part> freeParts = new ArrayList<Part>();
for (int i = 0; i < NB_CILIUM; i++) {
tabCilium[i] = new Cilium(i * TWO_PI / NB_CILIUM);
mouseSpeed = dist(mouseX, mouseY, pmouseX, pmouseY);
Rspeed = ((R += Rspeed) > 255 || (R < 0)) ? -Rspeed : Rspeed;
Gspeed = ((G += Gspeed) > 255 || (G < 0)) ? -Gspeed : Gspeed;
Bspeed = ((B += Bspeed) > 255 || (B < 0)) ? -Bspeed : Bspeed;
for (int i = freeParts.size () - 1; i > -1; i--) {
Boolean dead = freeParts.get(i).update();
for (int i = 0; i < NB_CILIUM; i++) {
for (int i = tabCilium[0].NB_POINTS-1; i >= 0; i--) {
for (int j = 0; j < NB_CILIUM; j++) {
Rspeed = (random(1) > .5 ? 1 : -1) * random(.8, 1.5);
Gspeed = (random(1) > .5 ? 1 : -1) * random(.8, 1.5);
Bspeed = (random(1) > .5 ? 1 : -1) * random(.8, 1.5);
final int NB_POINTS = 38;
final float POINTS_DIST = 4.2;
final float AMPLITUDE = random(1.5, 2);
final float MIN_SPEED = .12, MAX_SPEED = .4;
final float STEP = random(.02, .12);
final float PERIODS = random(2, 2);
final float s = TWO_PI * PERIODS / NB_POINTS;
float sinTheta, cosTheta;
float time = random(123456);
float colorAdjust = random(0, 20);
float [] diams = new float[NB_POINTS];
PVector[] pos = new PVector[NB_POINTS];
PVector lastMove = new PVector(0, 0);
color[] colors = new color[NB_POINTS];
Part[] parts = new Part[NB_POINTS];
for (int i = 0; i < NB_POINTS; i++){
pos[i] = new PVector(0, 0);
diams[i] = sqrt(25*(NB_POINTS-i));
D = new PVector(POINTS_DIST*cosTheta, POINTS_DIST*sinTheta);
pos[0] = new PVector(mouseX + CELL_RAD * cosTheta, mouseY + CELL_RAD * sinTheta);
for (int i = 1; i < NB_POINTS; i++)
delta = new PVector(pos[i].x - pos[i-1].x, pos[i].y - pos[i-1].y);
coeff = map(i, NB_POINTS, 0, MIN_SPEED, MAX_SPEED);
delta.x -= coeff * (delta.x - D.x);
delta.y -= coeff * (delta.y - D.y);
tmpX = i * PERIODS / NB_POINTS;
tmpY = AMPLITUDE * sin(i * s + time) * cos(HALF_PI + HALF_PI * i / NB_POINTS);
delta.x += tmpX * cosTheta - tmpY * sinTheta;
delta.y += tmpX * sinTheta + tmpY * cosTheta;
lastMove.sub(pos[NB_POINTS-2]);
lastMove.mult(POINTS_DIST);
for (int i = NB_POINTS-2; i > -1; i --) {
if (parts[NB_POINTS-1] != null) {
parts[NB_POINTS-1].pos = pos[NB_POINTS-1].get();
parts[NB_POINTS-1].speed = lastMove;
freeParts.add(parts[NB_POINTS-1]);
parts[NB_POINTS-1] = null;
if (random(1) < map(mouseSpeed, 0, width/2, .01, 2.5)) {
parts[0] = new Part(pos[0]);
lastMove = pos[NB_POINTS - 1].get();
if (parts[p_rank] == null) {
int c = colors[p_rank], dc = 42;
stroke(red(c)-dc, green(c)-dc, blue(c)-dc, map(p_rank, 0, NB_POINTS - 1, 120, 250));
colors[p_rank] = color(constrain(R, 0, 255), constrain(G, 0, 255), constrain(B, 0, 255));
} else if (p_rank == 1) {
colors[p_rank] = color(colorAdjust+R, colorAdjust+G, colorAdjust+B);
colors[p_rank] = colors[p_rank-1];
ellipse(pos[p_rank].x, pos[p_rank].y, diams[p_rank], diams[p_rank]);
PVector pos, speed = new PVector(0, 0);
int age = 0, lifetime = (int)random(50, 160), downAge;
float maxY = random(.1, .3);
float diam1 = map(age, 0, lifetime, 10, 2);
ellipse(pos.x, pos.y, diam1, diam1);
if (!down && pos.y < maxY*height) {
stroke(200, map(maxY, .1, .3, 30, 5));
diam1 = map(age, downAge, lifetime, 22, 2);
float diam2 = map(age, downAge, lifetime, 5, 0);
ellipse(pos.x, pos.y, diam1, diam2);
return age > lifetime || pos.x < 0 || pos.x > width || pos.y > height;