xxxxxxxxxx
105
const trail = [];
let heading = null;
let endHeading = null;
function setup() {
createCanvas(600, 600);
trail.push(createVector(0, 0));
heading = createVector(1, 0);
endHeading = heading;
}
function draw() {
trail.unshift(
trail[0].copy().add(
createVector(mouseX, mouseY).sub(trail[0]).mult(0.4)
)
);
if (trail.length > 50) {
trail.pop();
}
if (trail.length > 1) {
const diff = trail[0].copy().sub(trail[Math.min(5, trail.length-1)]);
if (diff.mag() > 0) {
heading = diff.normalize();
}
const rearDiff = trail[trail.length-Math.min(5, trail.length-1)].copy().sub(trail[trail.length-1]);
if (rearDiff.mag() > 0) {
endHeading = rearDiff.normalize();
}
}
trail.forEach((pt, i) => {
const distFromHead = pt.copy().sub(trail[0]).mag();
const alpha = 1/Math.pow(distFromHead + 3, 2);
const pos = pt.copy().mult(1 - alpha).add(
trail[0].copy().add(heading.copy().mult(-20*i)).mult(alpha)
);
trail[i] = pos;
});
let totalLength = 0;
for (let i = 1; i < trail.length; i++) {
totalLength += trail[i].copy().sub(trail[i-1]).mag();
}
background(220);
noFill();
stroke(0);
strokeJoin(ROUND);
strokeCap(ROUND);
const thickness = 20 + 100/(totalLength/40 + 1);
strokeWeight(thickness);
beginShape();
trail.forEach(pt => vertex(pt.x, pt.y));
endShape();
const stretch = Math.min(totalLength/40, 1.35);
push();
translate(trail[0].x, trail[0].y);
rotate(heading.heading());
translate(-120/thickness, 0);
scale(1 * stretch, 1 / stretch);
strokeWeight(10);
line(0, 0, 15, -50);
line(-15, 0, 0, -50);
noStroke();
fill(0);
circle(0, -15, 30);
[-1, 1].forEach(side => {
push();
scale(side, 1);
fill(0);
beginShape();
vertex(0, 5);
vertex(10, 50);
vertex(20, 5);
endShape(CLOSE);
circle(10, -10, 30);
fill(255);
circle(15, 0, 10);
pop();
});
pop();
push();
translate(trail[trail.length-1].x, trail[trail.length-1].y);
rotate(endHeading.heading());
translate(-120/thickness, 0);
scale(1 * stretch, 1 / stretch);
stroke(0);
noFill();
strokeWeight(10);
line(0, 0, -15, -50);
line(15, 0, 0, -50);
bezier(0, 0, 0, 100, -50, 100, -50, 50);
pop();
}