Assignment 3 – Generative Art

Concept

Last semester, I was doing my study away in New York and when the semester ended, I decided to travel to the other end of the country to San Francisco, because why not. While I was there, one of the many places on my checklist was the Golden Gate Park. Inside it was a Japanese Tea Garden. It was one of the most aesthetically pleasing and peaceful places I have ever been. One of the many things I really liked about that tea garden were the unique Japanese trees that it had, and so, as a small tribute of remembrance, I tried to make a Japanese tree of my own for this project.

Implementation

I started off by making the basic shapes for the background. I placed the rectangles for the window, pot, sky, wall and circles for the moon. The main part however, were the leaves. To keep it simple, I made a very basic Class for a circular leaf and then went on to add the functions for its movement and appearance. the idea I had was to fill up different clusters of leaves for the tree. I made three clusters or regions of leaves, each having their own set of leaves. The leaves would fall from the clusters in a random fashion and subsequently be deleted from the array when they exit the canvas from the bottom. I also decided it was a good idea to make use of noise for the first time to make the fall seem more natural. So I went on and added noise in the x-direction while making the leave travel downwards simultaneously.

However straightforward this may seem, I encountered quite a few bugs along the way and thankfully managed to resolve them. I will share the significant ones here.

Positioning the Leaves

I started off by creating the x0 and y0 coordinates for the center of the cluster where the leaf object would be. I also specified the clusterWidth and clusterHeight in the leaf’s constructor. The initial position of the leaf was placed randomly in the cluster by selecting a random position in the rectangular area bounded by it:

class Leaf {
  // x0 and y0 specify the center of the cluster of leaves (one of the 3 clusters)
  constructor(x0, y0, clusterWidth, clusterHeight) {
...

Following this, I found out that I had to use a separate variable to store this initial x-position since I was making use of noise in the move() function of the leaf’s class. I couldn’t add the xPos variable to itself to update its value since that would enlarge it too abruptly inside the draw function thanks to the noise() function. It took me quite some while to figure this out as this wasn’t a very straightforward bug, but I eventually got there:

// using a separate variable for the initial position of x since xPos will
    // always be changing in draw() and this will cause abrupt behavior in the
    // leaf's x-movement if used along with noise inside move()

    // positioning initialX, xPos, and yPos within the cluster
    this.initialX = random(x0 - clusterWidth, x0 + clusterWidth);
    this.xPos = random(x0 - clusterWidth, x0 + clusterWidth);
    this.yPos = random(y0 - clusterHeight, y0 + clusterHeight);

...

// for the leaf's falling movement
  move() {
    // only make the leaf fall if the fall attribute of the object is true
    if (this.fall) {
      // giving some noise in the x direction to give a natural feel while falling
      this.xPos = this.initialX + noise(this.xoff) * 100;
      this.xoff += this.xincrement;
      // incrementing y to make the leaf fall vertically
      this.yPos += this.ySpeed;
    }
Removing the Leaves

Since I was keeping a check both on whether a leaf is alive or not and whether it is falling or not, I had to implement both of these concurrently. For instance, if a leaf reached the end of the canvas and it got deleted from the array, the code that randomly chooses a leaf to fall would not know whether the leaf is alive or not and could encounter an empty object. So I added a check for whether the leaf is alive before making it fall and it fixed the bug that I was facing. Moreover, if the leaves[] array becomes empty, the random(0, leaves.length) would return zero and that would cause an error again since the element at index zero doesn’t exist. So I added a check for that as well:

// choosing a random leaf to fall every 20 frames

  // if the leaves[] array becomes empty, it causes an error because the length is 0 but
  // the 0th element doesn't exist anymore so we provide a check for that as well

  if (frameCount % 20 == 0 && leaves.length != 0) {
    // choosing a random leaf index to make it fall from the tree
    index = int(random(0, leaves.length));

    // check if the leaf at the random index is alive and present inside the array
    if (leaves[index].alive) {
      // if yes then make the leaf fall
      leaves[index].fall = true;
    }
  }
Randomizing Leaf Color

At first I tried to do this within the Leaf class itself but then I realized that if I choose the color inside the draw() function of the Leaf class, it would cause the leaf to change color continuously because the draw() function loops continuously. I couldn’t place the array inside the standard draw() function either for the same reason. So I came up with the idea of creating a global array that would store the two leaf colors (shades of purple) and then choose the color inside the attributes of the leaf class as a this.color attribute:

// array which stores the two shades of purple for the leaves
let leafColors = ["#963990", "#4B2454"];

class Leaf {
  // x0 and y0 specify the center of the cluster of leaves (one of the 3 clusters)
  constructor(x0, y0, clusterWidth, clusterHeight) {

...

    // choosing a random shade of purple from the two specified in the global array
    this.color = leafColors[int(random(0, 2))];
  }

...

// drawing the leaf
  draw() {
    noStroke();
    fill(this.color);
    ellipse(this.xPos, this.yPos, this.width, this.height);
  }

Reflection

I feel like I managed to get the kind of aesthetic feel I was going for in this assignment. The color combinations worked really well and the tree stood out within a minimalistic background without being too overwhelming. I went for a kind of peaceful and calm feel and the falling leaves did well to prortray that feeling as well. It was unfortunate that I had to start from scratch after losing progress mid-assignment but gladly I was able to recall the functions I made and how I implemented them. It was disheartening at first but after putting in some extra hours I was able to remake the project exactly how I wanted to in the first place. As for the future, I would definitely like to save my progress often and make the habit of hitting the save shortcut from time-to-time, although it sounds trivial but its something i would definitely like to work on. Excited to see what I can do with transformations for our next assignment!

 

Leave a Reply