Last active
July 14, 2017 00:43
-
-
Save JoshuaSullivan/10ebf533032b27416683abbe97353106 to your computer and use it in GitHub Desktop.
As the system matures, it gains increasingly complex behavior…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
final int PILLAR_ORDER = 8; | |
final int DIAGONALS = PILLAR_ORDER * 2 - 1; | |
final float PILLAR_WIDTH = 30.0; | |
final float PILLAR_HEIGHT = 15.0; | |
final float PILLAR_SPACING = 2.0; | |
final float GRAVITY = -1.0; | |
final float ELASTICITY = -0.6; | |
final float MAX_HEIGHT = 500.0; | |
final int TOTAL_RINGS = int(ceil(float(PILLAR_ORDER) / 2)); | |
final int DELAY = 200; | |
class Pillar { | |
float velocity, height, hue; | |
Pillar() { | |
velocity = 0.0; | |
height = 0.0; | |
hue = random(360.0); | |
} | |
void pop(float popVelocity) { | |
velocity += popVelocity; | |
} | |
void update() { | |
if (velocity == 0.0 && height == 0.0) { | |
// At rest. | |
return; | |
} | |
velocity += GRAVITY; | |
height += velocity; | |
if (height <= 0) { | |
// Bounce! | |
height = 0.0; | |
velocity *= ELASTICITY; | |
if (velocity < abs(GRAVITY)) { | |
velocity = 0.0; | |
} | |
} else if (height >= MAX_HEIGHT) { | |
// Bounce off ceiling. | |
height = MAX_HEIGHT; | |
velocity *= ELASTICITY; | |
} | |
} | |
void draw() { | |
if (height == 0.0 && velocity == 0.0) { | |
return; | |
} | |
float pw = PILLAR_WIDTH / 2.0; | |
float ph = PILLAR_HEIGHT / 2.0; | |
float h = round(height); | |
noStroke(); | |
color c; | |
if (h > 0.0) { | |
c = color(hue, 20, 100, 100); | |
fill(c); | |
quad(0, 0, -pw, -ph, -pw, -(h + ph), 0, -h); | |
c = color(hue, 40, 100, 100); | |
fill(c); | |
quad(0, 0, pw, -ph, pw, -(h + ph), 0, -h); | |
} | |
float hRatio = h / MAX_HEIGHT; | |
c = color(hue, 4 + 10 * hRatio, 100, 100); | |
fill(c); | |
quad(0, -h, -pw, -(h + ph), 0, -(h + pw), pw, -(h + ph)); | |
} | |
} | |
float[] offsets; | |
int pillarCount; | |
Pillar[] pillars; | |
Pillar[][] pillarGrid; | |
int lastPop = 0; | |
int popIndex = 0; | |
int animationType = 0; | |
final int animationTypeCount = 6; | |
void setup() { | |
size(300, 640); | |
colorMode(HSB, 360, 100, 100, 100); | |
pillarCount = PILLAR_ORDER * PILLAR_ORDER; | |
pillars = new Pillar[pillarCount]; | |
pillarGrid = new Pillar[pillarCount][pillarCount]; | |
for (int i = 0; i < pillarCount; i++) { | |
pillars[i] = new Pillar(); | |
} | |
int index = 0; | |
float rowCount = 0.0; | |
offsets = new float[pillarCount * 2]; | |
float pw = PILLAR_WIDTH / 2.0 + PILLAR_SPACING; | |
float ph = -(PILLAR_HEIGHT / 2.0 + PILLAR_SPACING); | |
for (int i = 0; i < PILLAR_ORDER; i++) { | |
float xOffset = float(i) * -pw; | |
for (int j = 0; j <= i; j++) { | |
// Calculate the offset for this pillar. | |
float x = j * (PILLAR_WIDTH + 2.0 * PILLAR_SPACING) + xOffset; | |
float y = rowCount * ph; | |
offsets[index * 2] = x; | |
offsets[index * 2 + 1] = y; | |
index++; | |
} | |
rowCount += 1.0; | |
} | |
for (int i = PILLAR_ORDER - 2; i >= 0; i--) { | |
float xOffset = float(i) * -pw; | |
for (int j = 0; j <= i; j++) { | |
float x = j * (PILLAR_WIDTH + 2.0 * PILLAR_SPACING) + xOffset; | |
float y = rowCount * ph; | |
offsets[index * 2] = x; | |
offsets[index * 2 + 1] = y; | |
index++; | |
} | |
rowCount+= 1.0; | |
} | |
int[] rowCounts = new int[PILLAR_ORDER]; | |
int gridLoops = 2 * PILLAR_ORDER - 1; | |
int pillarIndex = 0; | |
for (int i = 0; i < gridLoops; i++) { | |
// Place into the pillar grid; | |
int gridRow = min(i, PILLAR_ORDER - 1); | |
while (gridRow >= 0 && rowCounts[gridRow] < PILLAR_ORDER) { | |
int count = rowCounts[gridRow]; | |
pillarGrid[gridRow][count] = pillars[pillarIndex]; | |
rowCounts[gridRow]++; | |
pillarIndex++; | |
gridRow--; | |
} | |
} | |
float deltaHue = 360 / float(TOTAL_RINGS); | |
for (int i = 0; i < TOTAL_RINGS; i++) { | |
Pillar[] ring = getRing(i); | |
int ringCount = countForRing(i); | |
float hue = float(i) * deltaHue; | |
for (int j = 0; j < ringCount; j++) { | |
ring[j].hue = hue; | |
} | |
} | |
lastPop = millis(); | |
} | |
void draw() { | |
background(0, 0, 100, 100); | |
int now = millis(); | |
int timeSincePop = now - lastPop; | |
if (timeSincePop >= DELAY) { | |
int count = pillarCountForAnimation(animationType, popIndex); | |
Pillar[] group = pillarsForAnimation(animationType, popIndex); | |
for (int i = 0; i < count; i++) { | |
group[i].pop(12.0); | |
} | |
popIndex++; | |
lastPop = now; | |
if(popIndex == popCountForAnimation(animationType)) { | |
popIndex = 0; | |
lastPop += finalDelayForAnimation(animationType); | |
animationType = (animationType + 1) % animationTypeCount; | |
} | |
} | |
pushMatrix(); | |
translate(150, 630); | |
for (int i = pillarCount - 1; i >= 0; i--) { | |
pushMatrix(); | |
float x = offsets[i * 2]; | |
float y = offsets[i * 2 + 1]; | |
translate(x, y); | |
pillars[i].update(); | |
pillars[i].draw(); | |
popMatrix(); | |
} | |
popMatrix(); | |
} | |
Pillar[] pillarsForAnimation(int type, int index) { | |
switch (type) { | |
case 0: | |
// Diagonal: Bottom to Top | |
return getDiagonal(index, true); | |
case 1: | |
// Diagonal: Left to Right | |
return getDiagonal(index, false); | |
case 2: | |
// Rings: Outer to Inner | |
return getRing(index); | |
case 3: | |
// Diagonal: Top to Bottom | |
return getDiagonal(DIAGONALS - index - 1, true); | |
case 4: | |
// Diagonal: Right to Left | |
return getDiagonal(DIAGONALS - index - 1, false); | |
case 5: | |
// Rings: Inner to Outer | |
return getRing(TOTAL_RINGS - index - 1); | |
} | |
return new Pillar[0]; | |
} | |
int pillarCountForAnimation(int type, int index) { | |
switch(type) { | |
case 0: return countForDiagonal(index); | |
case 1: return countForDiagonal(index); | |
case 2: return countForRing(index); | |
case 3: return countForDiagonal(index); | |
case 4: return countForDiagonal(index); | |
case 5: return countForRing(TOTAL_RINGS - index - 1); | |
} | |
return 0; | |
} | |
int popCountForAnimation(int type) { | |
switch(type) { | |
case 0: return DIAGONALS; | |
case 1: return DIAGONALS; | |
case 2: return TOTAL_RINGS; | |
case 3: return DIAGONALS; | |
case 4: return DIAGONALS; | |
case 5: return TOTAL_RINGS; | |
} | |
return 0; | |
} | |
int finalDelayForAnimation(int type) { | |
switch(type) { | |
case 0: return DELAY; | |
case 1: return DELAY * 3; | |
case 2: return DELAY; | |
case 3: return DELAY; | |
case 4: return DELAY * 3; | |
case 5: return DELAY * 3; | |
} | |
return 0; | |
} | |
int countForRing(int index) { | |
int ringIndex = max(0, min(index, TOTAL_RINGS - 1)); | |
int i = PILLAR_ORDER - 2 * ringIndex; | |
int j = i - 2; | |
int total = i * i - j * j; | |
return total; | |
} | |
Pillar[] getRing(int index) { | |
int itemsToReturn = countForRing(index); | |
int count = 0; | |
Pillar[] pillarsToReturn = new Pillar[itemsToReturn]; | |
int min = index; | |
int max = PILLAR_ORDER - index - 1; | |
for (int i = 0; i < PILLAR_ORDER; i++) { | |
for (int j = 0; j < PILLAR_ORDER; j++) { | |
if (i >= min && i <= max && j >= min && j <= max && (i == min || i == max || j == min || j == max)) { | |
pillarsToReturn[count] = pillarGrid[i][j]; | |
count++; | |
} | |
} | |
} | |
return pillarsToReturn; | |
} | |
Pillar[] getRow(int index) { | |
Pillar[] pillarsToReturn = new Pillar[PILLAR_ORDER]; | |
for (int i = 0; i < PILLAR_ORDER; i++) { | |
pillarsToReturn[i] = pillarGrid[i][index]; | |
} | |
return pillarsToReturn; | |
} | |
Pillar[] getColumn(int index) { | |
Pillar[] pillarsToReturn = new Pillar[PILLAR_ORDER]; | |
for (int i = 0; i < PILLAR_ORDER; i++) { | |
pillarsToReturn[i] = pillarGrid[index][i]; | |
} | |
return pillarsToReturn; | |
} | |
Pillar[] getDiagonal(int index, boolean topToBottom) { | |
println("topToBottom:", topToBottom); | |
index = max(0, min(index, DIAGONALS - 1)); | |
int count = countForDiagonal(index); | |
println("Diagonal", index, "contains", count, "columns."); | |
Pillar[] pillarsToReturn = new Pillar[count]; | |
int x, y; | |
if (index < PILLAR_ORDER) { | |
x = topToBottom ? index : PILLAR_ORDER - 1; | |
y = topToBottom ? 0 : index; | |
} else { | |
x = topToBottom ? PILLAR_ORDER - 1 : DIAGONALS - index - 1; | |
y = topToBottom ? index - PILLAR_ORDER + 1 : PILLAR_ORDER - 1; | |
} | |
println("Starting at [", x, ",", y, "]"); | |
for (int i = 0; i < count; i++) { | |
int xi = x + (topToBottom ? -i : -i); | |
int yi = y + (topToBottom ? i : -i); | |
//println(i, ":", xi, ",", yi); | |
pillarsToReturn[i] = pillarGrid[xi][yi]; | |
} | |
return pillarsToReturn; | |
} | |
int countForDiagonal(int index) { | |
index = max(0, min(index, DIAGONALS - 1)); | |
if (index < PILLAR_ORDER) { | |
return index + 1; | |
} else { | |
return DIAGONALS - index; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment