class Vine { Tri[] tris; Vine( float startX, float startY, float triSideRadius, float triPadding, float rotationOffset, float timeDelay, float radiusGrowthRate, float rotateSpeed, float bend, float initialAngle, int num) { tris = new Tri[num]; TriNorms norms = new TriNorms(); norms.r = triSideRadius*2; norms.radiusGrowthRate = radiusGrowthRate; norms.rotateSpeed = rotateSpeed; norms.rotationOffset = rotationOffset; norms.alternateSpin = false; float stepLength = triSideRadius*2+triPadding; float x = startX, y = startY, theta = 0, bendTheta = initialAngle; for(int i = 0; i < tris.length; i++) { tris[i] = new Tri(x,y, bendTheta+PI/6, i*timeDelay, i%2 == 0, norms); switch(i%4) { case 0: bendTheta += PI/3; break; case 1: bendTheta -= PI/3; break; case 2: bendTheta -= PI/3; break; case 3: bendTheta += PI/3; break; } x += stepLength*cos(bendTheta); y += stepLength*sin(bendTheta); bendTheta += bend; } } void next(float now) { for(int i = 0; i < tris.length; i++) { tris[i].next(now); } } void draw() { for(int i = 0; i < tris.length; i++) { tris[i].draw(); } } } class TriNorms { float r; float radiusGrowthRate; float rotateSpeed; float rotationOffset; boolean alternateSpin; } class Tri { float x, y, r, startTime; float startTheta, goalTheta, theta; boolean finished; TriNorms norms; Tri(float x, float y, float theta, float startTime, boolean even, TriNorms norms) { this.x = x; this.y = y; this.startTheta = theta - norms.rotationOffset*(even && norms.alternateSpin ? 1 : -1); this.goalTheta = theta; this.theta = startTheta; this.r = 0; this.startTime = startTime; this.norms = norms; this.finished = false; } void next(float now) { if(now > startTime && !finished) { if(r < norms.r) { r = interpolate(0, norms.r, (now-startTime)*norms.radiusGrowthRate); } else { r = norms.r; } if(abs(theta-goalTheta) > 0.01) { theta = interpolate(startTheta, goalTheta, (now-startTime)*norms.rotateSpeed); } else { theta = goalTheta; } if(r == norms.r && theta == goalTheta) { finished = true; } } } void draw() { float p1x = x+cos(theta-PI/6)*r, p1y = y+sin(theta-PI/6)*r, p2x = x+cos(theta+PI/2)*r, p2y = y+sin(theta+PI/2)*r, p3x = x+cos(theta+PI*7/6)*r, p3y = y+sin(theta+PI*7/6)*r; triangle(p1x,p1y,p2x,p2y,p3x,p3y); } } float interpolate(float start, float end, float amount) { float camount = cos(amount*PI)*-0.5+0.5; return lerp(start, end, camount); } float GRID_X = cos(PI/6); float GRID_Y = sin(PI/6); Vine[] vines; int now = 0; void setup() { size(128,128); smooth(); makeVines(); } void makeVines() { vines = new Vine[] { new Vine( 68, // start x 28, // start y 5, // distance from triangle center to side 0.1, // padding between triangles PI, // rotation from creation to goal 0.3, // delay between growth start 0.6, // rate of growth of triangles 0.25, // speed of rotation of triangles, 0.224, // bend 0.2, // initial angle 28 // total triangles ) }; now = 0; } void draw() { drawVines(); } void drawVines() { background(0); noStroke(); fill(255,255,255,100); for(int i = 0; i < vines.length; i++) { vines[i].next(now*0.1); vines[i].draw(); } /* if(now%2 == 0 && now > 80 && now <= 90) { saveFrame("star-shapes-###.png"); } */ now += 1; } void mousePressed() { println(now); makeVines(); }