xxxxxxxxxx
161
let midX;
let midY;
const CYCLE_COLORS = ["#FFB6C1", "#98FFE3", "#A7C7E7", "#FFB347", "#B4EEB4"];
let direction = 0;
let increment = 10;
let lastPoint = {};
let garbageCollector = [];
let LINE_LIFETIME = 250;
let LINE_DECREMENT = 25;
let lightCycles = [];
let numCycles = 5;
function setup() {
createCanvas(400, 400);
background(0);
frameRate(10);
midX = width / 2;
midY = height / 2;
lastPoint = { x: midX, y: midY };
// Clear existing arrays
garbageCollector = [];
lightCycles = [];
for (let i = 0; i < numCycles; i++) {
lightCycles.push(new LightCycle(CYCLE_COLORS[i % CYCLE_COLORS.length]));
}
}
class LightCycle {
constructor(color) {
this.color = color;
this.respawn();
}
move() {
let randVal = Math.random();
let xDelta = 0;
let yDelta = 0;
if (randVal < 0.8) {
// Keep direction
} else if (randVal < 0.9) {
this.direction = (this.direction + 90) % 360;
} else {
this.direction = (this.direction - 90 + 360) % 360;
}
if (this.direction === 0) {
xDelta = increment;
} else if (this.direction === 90) {
yDelta = increment;
} else if (this.direction === 180) {
xDelta = -increment;
} else if (this.direction === 270) {
yDelta = -increment;
}
let newPoint = {
x: this.position.x + xDelta,
y: this.position.y + yDelta,
};
let collectorPoint = {
x1: this.position.x,
y1: this.position.y,
x2: newPoint.x,
y2: newPoint.y,
counter: LINE_LIFETIME,
color: this.color,
};
stroke(this.color);
line(this.position.x, this.position.y, newPoint.x, newPoint.y);
if (this.checkCollision(newPoint)) {
this.respawn();
} else {
this.position = newPoint;
}
garbageCollector.push(collectorPoint);
}
respawn() {
const borderMargin = 0.1;
const minX = width * borderMargin;
const maxX = width * (1 - borderMargin);
const minY = height * borderMargin;
const maxY = height * (1 - borderMargin);
this.position = {
x: Math.round(random(minX, maxX) / 10) * 10,
y: Math.round(random(minY, maxY) / 10) * 10,
};
this.direction = [0, 90, 180, 270][Math.floor(Math.random() * 4)];
}
checkCollision(newPoint) {
// check for out of bounds
if (
Math.abs(newPoint.x - midX) > midX ||
Math.abs(newPoint.y - midY) > midY
) {
return true;
}
// check for line intersection
for (let i = 0; i < garbageCollector.length; i++) {
if (
(newPoint.x == garbageCollector[i].x1 &&
newPoint.y == garbageCollector[i].y1) ||
(newPoint.x == garbageCollector[i].x2 &&
newPoint.y == garbageCollector[i].y2)
) {
return true;
}
}
return false;
}
}
function draw() {
for (let i = 0; i < lightCycles.length; i++) {
lightCycles[i].move();
}
// Tail management
let nextDel = 0;
for (let i = 0; i < garbageCollector.length; i++) {
// decrement the point value
point = garbageCollector[i];
point.counter -= LINE_DECREMENT;
// First draw black to erase
stroke(0);
strokeWeight(2);
line(point.x1, point.y1, point.x2, point.y2);
strokeWeight(1);
// Draw the colored line with opacity
let c = color(point.color);
c.setAlpha(point.counter);
stroke(c);
line(point.x1, point.y1, point.x2, point.y2);
// garbage collect
if (point.counter <= 0) {
nextDel = i;
}
}
// trim negative counters
if (nextDel > 0) {
garbageCollector.splice(0, nextDel);
}
}