const ColorPalette = Object.freeze({
createCanvas(windowWidth, windowHeight);
for(let i = 0; i<numSalamanders; i++){
let speed = random(2.0, 4.0);
let numSections = floor(random(10, 16));
let col = lerpColor(color(ColorPalette.yellow), color(ColorPalette.red), random());
let salamander = new Salamander(numSections, lenSection, speed, 30.0, 40.0 / speed, numSections * lenSection * 0.25, i, col);
salamanders.push(salamander);
background(ColorPalette.blue);
for(let i = 0; i<salamanders.length; i++){
let salamander = salamanders[i];
for(let i = 0; i<salamanders.length; i++){
let salamander = salamanders[i];
for(let i = 0; i<salamanders.length; i++){
let salamander = salamanders[i];
constructor(salamander, footSet, index, length, angle, maxStep, right, isFront, color){
this.salamander = salamander;
this.pos = createVector();
this.goal = createVector();
this.pos = this.getStepPos();
let pos1 = this.salamander.sections[this.index];
let pos = this.getStepPos();
let dist = this.pos.dist(pos1);
otherFoot = this.footSet.lfoot;
otherFoot = this.footSet.rfoot;
if((dist > this.length && otherFoot.move == false)){
let npos = p5.Vector.lerp(this.pos, this.goal, this.step / this.maxStep);
if(this.step > this.maxStep){
let pos1 = this.salamander.sections[this.index];
let pos2 = this.salamander.sections[this.index-1];
let dir = p5.Vector.sub(pos2, pos1);
let col = lerpColor(this.color, color(ColorPalette.darkgreen),0.1);
strokeWeight(this.length * 0.25);
let bpos = this.salamander.sections[this.index];
let fpos = this.pos.copy();
if(bpos.dist(fpos) > this.length){
let bendlen = sqrt(max(pow(this.length, 2) - pow(bpos.dist(fpos), 2), 0)) / 2.0;
let bdir = p5.Vector.sub(fpos, bpos);
let mpos = p5.Vector.mult(p5.Vector.add(bpos, fpos), 0.5);
if((this.isFront && this.right) || (this.isFront == false && this.right == false) ){
line(bpos.x, bpos.y, mpos.x, mpos.y);
line(mpos.x, mpos.y, fpos.x, fpos.y);
this.drawFoot(fpos, p5.Vector.sub(fpos, mpos), this.length * 0.25, col);
drawFoot(pos, dir, size, col){
let rotang = atan2(dir.y, dir.x);
let stepang = radians(45.0);
for(let i=-1; i<=1; i++){
let fx = cos(ang) * size;
let fy = sin(ang) * size;
strokeWeight(this.length * 0.15);
constructor(alien, index, length, angle, maxStep, isFront, color){
this.lfoot = new Foot(alien, this, index, length, -angle, maxStep, false, isFront, color);
this.rfoot = new Foot(alien, this, index, length, angle, maxStep, true, isFront, color);
if(this.rfoot.move == true){
val = this.rfoot.step / this.rfoot.maxStep;
val = -this.lfoot.step / this.lfoot.maxStep;
constructor(numSections, lenSection, speed, angle, maxStep, footLength, index, color){
this.numSections = numSections;
this.lenSection = lenSection;
this.vel = createVector(speed, 0);
this.acc = createVector();
this.backFootIndex = floor(numSections * 0.5);
let basePos = createVector(random(0, width), random(0, height));
for (let i=0; i< numSections; i++){
let pos = createVector(basePos.x - i * lenSection, basePos.y);
if(i == this.frontFootIndex || i == this.backFootIndex){
if(i == this.frontFootIndex){isFront = true;}
let footSet = new FootSet(this, i, footLength, radians(angle), maxStep, isFront, color);
this.footSets.push(footSet);
let x = noise(frameCount * smoothness + this.index * 724) - 0.5;
let y = noise(frameCount * smoothness + this.index * 724 + 5234) - 0.5;
let sdir = createVector(x, y);
let bdir = createVector();
if (this.sections[0].x < bound){
bdir.add(createVector(pow((1.0 - this.sections[0].x / bound), 2), 0));
if (this.sections[0].x > windowWidth - bound){
bdir.add(createVector(-pow((1.0 - (windowWidth - this.sections[0].x) / bound), 2), 0));
if (this.sections[0].y < bound){
bdir.add(createVector(0, pow((1.0 - this.sections[0].y / bound), 2)));
if (this.sections[0].y > windowHeight - bound){
bdir.add(createVector(0, - pow((1.0 - (windowHeight - this.sections[0].y) / bound), 2)));
bdir.mult(this.speed * 2);
this.vel.limit(this.speed);
for(let i=0; i < this.sections.length; i++){
this.sections[i].add(this.vel);
let pos1 = this.sections[i-1];
let pos2 = this.sections[i];
let movpos = p5.Vector.sub(pos2, pos1);
movpos.mult(this.lenSection);
this.sections[i] = movpos;
let pos1 = this.sections[this.footSets[0].index];
let pos2 = this.sections[this.footSets[1].index];
let cen = p5.Vector.mult(p5.Vector.add(pos1, pos2), 0.5);
let maxSize = this.numSections * this.lenSection * 0.8;
let col1 = color(ColorPalette.red);
let col2 = color(ColorPalette.blue);
for(let i=numShadow-1; i>=0; i--){
let col = lerpColor(col1, col2, pow(i / numShadow, 0.2));
let size = map(i, 0, numShadow-1, 0, maxSize);
ellipse(cen.x, cen.y, size, size);
for(let i=0; i<this.footSets.length; i++){
let footSet = this.footSets[i];
for(let i= 0; i< this.sections.length; i++){
let section1 = this.sections[i];
if(i < this.sections.length -1){
section2 = this.sections[i+ 1];
this.drawHead(section1, p5.Vector.sub(section1, section2), this.lenSection * this.numSections * 0.09);
}else if(i < this.backFootIndex){
let bodySize = this.lenSection * this.numSections * 0.13;
let bval = sin(map(i, 1, this.backFootIndex - 1.0, 0.0, PI));
let bscale = map(bval, 0, 1.0, 0.9, 1.0);
ellipse(section1.x, section1.y, bodySize, bodySize);
let tailSize = this.lenSection * this.numSections * 0.10;
let sval = map(i, this.backFootIndex, this.sections.length-1, tailSize, tailSize * 0.2);
ellipse(section1.x, section1.y, sval, sval);
drawHead(pos, dir, size){
let rotang = atan2(dir.y, dir.x);
rotate(rotang - HALF_PI);
for(let i=0; i<res; i++){
let ang = i / res * TWO_PI;