Gif quality is low, checkout the original in YouTube or Pixabay for nicer splashing
To skip to the code, click here.
When my brother passed away of a sudden heart attack at age 38, we were all devastated. One of the things I have done in the years following is death is create and upload a video of a song that he wrote.
I think I need someone to bleed with me on brand new sheets of silk
I think I need someone to feed me homemade cakes and milk
I think I need someone to hold me while I free myself
I think I’ll need, and then I’ll fold me and lay me on a shelf
While most of the video was the text of the song, I also used two Processing animations for the video. One was growing and flowering vines. The other, which is also the ending of the video, is the Flood of Tears (link is to Pixabay).
Tears fall and splash in a growing puddle that takes over the screen until it’s filled. Because sometimes, grief knows no bounds.
And for the last few months, grief, for completely different reasons, has been all-encompassing. So I revisited this code.
Sometimes code can give comfort.
Comfort in coding. Generated by Dall-E
Full code in GitHub
Check it out here.
Steps
So, how does the code work?
- Code to create a large drop — the tear.
- Code to create small droplets when hitting the puddle: The splash
- Code to create the flood of tears.
The tear
First, we need the shape of a tear. For this I used a custom PShape. The idea was to use a Bezier curve for the top left and top right — the “tear” — and half a circle for the bottom half of the tear:
void setup(){
size(400, 400);
background(0);
//drop PShape
drop = createShape();
drop.beginShape(); // start to draw a shape
drop.vertex(0, -50); // begin at this point x, y
//top left of drop, curving in then out
drop.bezierVertex(0, -50, 8, -25, 10, -20);
drop.bezierVertex(10, -20, 17, -10, 20, 0.3);
//bottom arc of drop
for (float a = 0; a < PI; a += 0.1) {
float r = 20;
drop.vertex(r*cos(a), r*sin(a));
}
//top right of drop, curving in then out
drop.bezierVertex(-20, 0.3, -17, -10, -10, -20);
drop.bezierVertex(-10, -20, -8, -25, 0, -50);
drop.endShape(CLOSE);
//PShapes are always drawn at 0,0, so need to translate to draw
pushMatrix();
translate(200, 200);
scale(0.5);
shape(drop);
popMatrix();
}
This results in the following:
Now we want a tear-y color. For that I played with blue, green and alpha:
float blue = random(280, 255);
float green = random(100, 200);
float alpha = random(150, 255);
drop.setFill(color(0, green, blue, alpha));
Now, I wanted it to drop:
//position, could use PVector instead
float x = 200;//center
float y = 10;//top
//drop
PShape drop;
//falling speed
float speed = 5;
//when to update the position - don't want it to fall too fast
long currTime = 0;
long prevTime = 0;
int interval = 50;//ms
...//here is the PShape code from before
void draw() {//draw and update
background(0);
//we want to draw all the time, and update if interval passed
currTime = millis();
//draw
pushMatrix();
translate(x, y);
scale(0.5);
shape(drop);
popMatrix();
//update if interval passed
if (currTime-prevTime > interval) {
prevTime = currTime;
y = y+speed;
}
}
And I also wanted it to shimmer, so I changed the alpha semi-randomly:
if (currTime-prevTime > interval) {
prevTime = currTime;
y = y+speed;
alpha = alpha + random(-10, +10);
alpha = constrain(alpha, 150, 255);
}
Now we need it to splash.
The splash
The splash is a few circular droplets. What is interesting about them is that they have an upward starting velocity, and then they fall with gravity. In other words, we need some basic physics.
class Droplet {
PVector pos; //position of droplet
PVector vel;//velocity of droplet
PVector gravity = new PVector(0, 10);//gravity
color c;//color of droplet
//create droplet with random velocity in splash-y direction
Droplet(PVector pos, color c) {
this.pos = pos;
this.c = c;
vel = new PVector(random(-20, 20), random(-30, -70));
}
//using given color to draw the droplet and update position and velocity.
void draw() {
fill(c);
noStroke();
circle(pos.x, pos.y, 10);
//physics:
//v = starting_velocity + gravity * time_unit
//time_unit is 1
vel.add(gravity);
pos.add(vel);
}
}
So when the Drop hits the puddle, we need to remove the drop, and create some random droplets instead.
The flood
The flood is actually simple. It’s a rectangle that starts with height 0 and grows bigger from below. As in Processing the top right corner is (0,0), we need to subtract the current height of the flood:
flood = height;//no flood
//when drop hits, subtact from flood:
flood -=10;
//draw flood
fill(0, 85, 255);
rect(0, flood, width, height - flood);
Flood of tears
I wanted it to feel like a flood, and have more and more tears over time. So I
start with an interval
of 3 seconds. After the interval
, I create a drop …
and make the interval shorter:
interval = int(0.8*interval);
And that gives the “more and more tears” effect.
Full code is here.
May we all know better times.
143 days.Still waiting. #BringThemHome .
Check out my free and open source online game Space Short. If you like my site, you can also buy me a coffee.