xxxxxxxxxx
// Dan the Man Shiffman's spring array (The Nature of Code Ch. 3),
// chasing the 'mover' object from sketch 151089 "Spinning tops" (Creative Coding Monash U)
// class, PVector, random, line, ellipse, sin, cos, generative
// No interaction, background clears every 3000 frames.
SpringTrail s;
Insect mover;
float opacity = 0;
boolean fade = false;
void setup() {
size(1300, 650);
colorMode(HSB, 360, 100, 100, 100);
background(20);
s = new SpringTrail();
mover = new Insect();
}
void draw() {
mover.move();
s.move(mover.x2, mover.y2);
if (frameCount % 3000 == 0) fade = true;
if (fade) fadeOut();
if (opacity > 100) reset();
}
void reset() {
fade = false;
opacity = 0;
background(20);
s.alpha = 0;
float min = random(300);
float max = min + 60;
for (Spring spr : s.springs) {
spr.hue = random(min, max);
}
}
void fadeOut() {
noStroke();
fill(20, opacity);
rect(0, 0, width, height);
opacity += .5;
}
// %%%%%%%%%%%%%%%%%%%%%%%%%% classes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
class Bob {
PVector pos;
PVector vel;
PVector accel;
float mass = 12;
float damping = 0.98;
Bob(float x, float y) {
pos = new PVector(x, y);
vel = new PVector();
accel = new PVector();
}
void update() {
vel.add(accel);
vel.mult(damping);
pos.add(vel);
accel.mult(0);
}
// Newton's law: F = M * A
void applyForce(PVector force) {
PVector f = force.get();
f.div(mass);
accel.add(f);
}
void display() {
noStroke();
fill(250, s.alpha);
ellipse(pos.x, pos.y, 1.5, 1.5);
}
void drag(float mx, float my) {
if (this == s.bobs[0]) {
pos.x = lerp(pos.x, mx, .2);
pos.y = lerp(pos.y, my, .2) ;
}
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
class Spring {
float len, k = 0.2, d, stretch;
Bob a, b;
PVector force;
float hue = random(60), sat, bri;
Spring(Bob ain, Bob bin, int l) {
a = ain;
b = bin;
len = l;
}
void update() {
force = PVector.sub(a.pos, b.pos);
d = force.mag();
stretch = d - len;
force.normalize();
force.mult(-1 * k * stretch); //Hooke's Law
a.applyForce(force);
force.mult(-1);
b.applyForce(force);
}
void display() {
strokeWeight(.5);
stroke (hue, sat, bri, s.alpha);
sat = 20 + abs(sin(frameCount * .1)) * 80;
bri = 100 - abs(sin(frameCount * .1)) * 60;
line(a.pos.x, a.pos.y, b.pos.x, b.pos.y);
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
class Insect {
float x, y, x2, y2, ang, max, min, radius, incr;
int edge, dir;
PVector pos, vel;
Insect() {
max = 3;
min = .1;
edge = 100;
pos = new PVector();
vel = new PVector(random(-2, 2), random(-2, 2));
dir = random(1) > 0.5 ? 1 : -1;
}
void move() {
update();
boundsCheck();
display();
}
void update() {
pos.add(vel);
if (frameCount % 180 == 0) dir = random(1) > 0.5 ? 1 : -1;
incr = random(.001, .02);
ang += incr;
x = pos.x + 100 * cos(ang);
y = pos.y + 100 * cos(ang);
radius = 100 * sin(ang*0.1);
x2 = x + radius * sin(ang*3*dir);
y2 = y + radius * cos(ang*3*dir);
}
void boundsCheck() {
if (pos.x > width-edge) vel.x = -random(min, max);
else if (pos.x < edge) vel.x = random(min, max);
if (pos.y > height-edge)vel.y = -random(min, max);
else if ( pos.y < edge)vel.y = random(min, max);
}
void display() {
stroke(#FA1919);
strokeWeight(2);
//line(pos.x, pos.y, x, y);
//line(x, y, x2, y2);
//fill(#FA1919);
//noStroke();
//ellipse(x, y, 5, 5);
//ellipse( x2, y2, 5, 5);
//ellipse( pos.x, pos.y, 15, 15);
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
class SpringTrail {
Bob[] bobs = new Bob[5];
Spring[] springs = new Spring[4];
float alpha = 0;
SpringTrail() {
for (int i = 0; i < bobs.length; i++) {
bobs[i] = new Bob(-5, i*20 + (height/2));
}
for (int i = 0; i < springs.length; i++) {
springs[i] = new Spring(bobs[i], bobs[i+1], 20);
}
}
void move(float x, float y) {
alpha += .2;
if (alpha > 100) alpha = 100;
for (Spring s : springs) {
s.update();
s.display();
}
for (Bob b : bobs) {
b.drag(x, y);
b.update();
b.display();
}
}
}