xxxxxxxxxx
153
let snail;
let sketchtime, delayFor = 1500;
let bgCol = '#020202';
function setup() {
createCanvas(600, 600);
snail = new Snail(width/2, height/2, 90, 3);
background(bgCol);
// frameRate(30);
}
function draw() {
if (snail.drawNext()) {
sketchtime = millis();
} else if (millis() - sketchtime > delayFor) {
background(bgCol);
let cdir = random() < 0.5 ? CW : CCW;
let rdir = random() < 0.5 ? INWARDS : OUTWARDS;
let rnd = random() < 0.4;
if (random() < 0.1) {
// New snail size
let nbrRings = floor(random(2, 8));
let triSize = 250 / nbrRings;
snail = new Snail(width/2, height/2, triSize, nbrRings);
}
snail.initSnail(cdir, rdir, rnd);
}
}
const CW = 0, CCW = 1, RANDOM = 2;
const INWARDS = 1, OUTWARDS = 0;
const integerComparitor = new Intl.Collator(undefined, { numeric : true }).compare;
class Snail {
constructor(cx, cy, triSize, nbrRings) {
this.cx = cx;
this.cy = cy;
this.triSize = triSize;
this.halfTriSize = this.triSize / 2;
this.triHeight = this.halfTriSize * Math.sqrt(3);
this.nbrRings = nbrRings;
this.makeTriList(nbrRings);
this.next = 0;
this.colOffset = 3;
this.sColor = '#FFF';
this.sWidth = 2;
this.colors = [
'#C00000', '#00C000', '#555555', '#0000C0', '#00AAAA', '#FFAA68'
];
this.initSnail(CW, OUTWARDS, false);
}
makeTriList(nr) {
this.rings = [6];
for (let i = 1; i < nr; i++)
this.rings[i] = this.rings[i-1] + 6 * (2 * i + 1);
this.nbrTris = this.rings[this.rings.length-1];
this.list = [];
for (let i = 0; i < this.nbrTris; i++)
this.list[i] = i;
}
initSnail(clockDir, radialDir, rnd) {
if (rnd) {
let idx = this.list.length - 1;
for (let idx = this.list.length - 1; idx > 0; idx--) {
let pos = Math.floor(random(0, idx));
let v0 = this.list[pos];
this.list[pos] = this.list[idx];
this.list[idx] = v0;
}
} else {
this.list.sort(integerComparitor);
if (radialDir == OUTWARDS) {
if (clockDir == CW) this.reverseClockDir();
} else {
if (clockDir == CCW) this.reverseClockDir();
this.list.reverse(integerComparitor);
}
}
this.next = 0;
this.colOffset = floor(random(0, this.colors.length));
}
reverseClockDir() {
for (let r = 0; r < this.nbrRings; r++) {
let idx0 = r == 0 ? 0 : this.rings[r - 1];
let idx1 = this.rings[r] - 1;
while (idx1 > idx0) {
let temp = this.list[idx0];
this.list[idx0] = this.list[idx1];
this.list[idx1] = temp;
idx0++;
idx1--;
}
}
}
drawNext() {
if (this.next >= this.nbrTris) return false;
let ringNo = 0;
let nbrInRing = 6;
// Work out which ring the triangle is in
let tn = this.list[this.next++];
while (tn >= nbrInRing) {
tn -= nbrInRing;
ringNo++;
nbrInRing = 6 * (2 * ringNo + 1);
}
// Now we know which ring it is in calculate the number
// of triangles per 60 degree segment and then the
// anitclockwise position within the segment
let nbrInSeg = 2 * ringNo + 1;
let segNo = Math.floor(tn / nbrInSeg);
let posInSeg = tn % nbrInSeg;
// Save the current matrix
push();
// Set the drawing attributes
fill(this.colors[(this.colOffset + tn) % this.colors.length]);
stroke(this.sColor);
strokeWeight(this.sWidth);
// now move to the centre of the snail and rotate snail for each segment
translate(this.cx, this.cy);
rotate(radians(-segNo * 60));
// Calculate the start drawing position
let py = this.halfTriSize * (ringNo - posInSeg);
let px = ringNo * this.triHeight;
// translate to start draw psotion
translate(px, py);
// Alternate triangles are flipped.
beginShape(TRIANGLES);
if (posInSeg % 2 == 0) {
vertex(0, 0);
vertex(this.triHeight, -this.halfTriSize);
vertex(this.triHeight, this.halfTriSize);
} else {
vertex(this.triHeight, 0);
vertex(0, - this.halfTriSize);
vertex(0, + this.halfTriSize);
}
endShape(CLOSE);
pop();
return true;
}
}