alt text

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. alt text

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:

alt text

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));

alt text

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;
      }
    }

alt text

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);
    }

alt text

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.

alt text

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.