Skip to content

Instantly share code, notes, and snippets.

@JoshuaSullivan
Last active July 14, 2017 00:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JoshuaSullivan/10ebf533032b27416683abbe97353106 to your computer and use it in GitHub Desktop.
Save JoshuaSullivan/10ebf533032b27416683abbe97353106 to your computer and use it in GitHub Desktop.
As the system matures, it gains increasingly complex behavior…
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