Simulating Butterfly Flutters

Butterfly Flutters

In this project, we simulate the fluttering motion of a butterfly by focusing on how acceleration could be used to control the movement.

Rules

  • A butterfly’s movement is influenced by unpredictable changes in its speed and direction, so we’ll randomize the acceleration over time.
  • While acceleration can be random, the butterfly doesn’t move too fast. We’ll use a damping factor to slow the object down.
  • The butterfly has to stay within the canvas, so we’ll implement boundary conditions to keep it in view.
  • By focusing on irregular accelerations and smooth decelerations, we can simulate the light, erratic fluttering of a butterfly.

Code

I’m particularly proud of how adding slight randomness to the acceleration makes the butterfly feel alive, without the need for overly complex design or physics.

let randomAcc = createVector(random(-1, 1), random(-1, 1));
this.acceleration.add(randomAcc);

// Update velocity based on acceleration
this.velocity.add(this.acceleration);

// Limit velocity to simulate fluttering motion, not too fast
this.velocity.limit(this.maxSpeed);

// Dampen the velocity slightly
this.velocity.mult(0.95);

link to code

Future improvements

  • I could improve the butterfly’s visual design by adding more details to the wings and body.
  • Adding mouse or keyboard interactions could let users “guide” the butterfly around the canvas.
  • Introducing environmental elements like wind or obstacles could add complexity and realism to the simulation.

Week 2 | Just bounce

Visit the sketch here!
Concept and Inspiration

In the second week, we tapped into the world of vectors. I wanted to make something simple that requires speed, velocity, and everything around us with such aspects. Our class starts with bouncing a ball, and I revisited this concept again this time by applying vectors. What I wanted to recreate is a ball object falling into the water and creating this ripple-like effect.

Sketch

How it works

Using vectors, we can have p5.js calculate the speed of the object. The concept of ‘gravity’ here can be attributed to the y-position of the ball. Each time the ball bounces, its y-position should be decreased by cutting it in half. For the bounce to feel smoother, we introduce a bounciness variable that multiplies with the y-position negatively.

// bounce by multiplying the speed by the bounciness
  if (position.y + diameter / 2 > height) {
    position.y = height - diameter / 2;
    speed.y *= -bounciness;
    speed.x *= bounciness;
  }
Challenges faced

The tutorial that I followed only introduced the concept of ‘gravity’ in scalar methods. Extracting this information, I transformed the modes from scalar to vector. It was quite interesting, and quite the challenge!

As I originally mentioned, I wanted to make the ball form ripples when touching a certain height. While creating the ripples itself is a simple task using for-loops, making sure that it stays without being refreshed by the background is a challenge that I still haven’t overcome yet.

I have been trying to implement a few things, but I do not want my code to become overcomplicated. While I still have the time, I’ll try some stuff up to see if fixing this is possible.

Edit: I finally fixed the ripple problem, check it out here.
Resources Used

Bouncing Ball Simulation – Jeff Thompson

Assignment 2- Spiral Repulsion

Concept

For this assignment, I was primarily inspired by the galaxy—a seemingly simple yet profoundly intricate phenomenon in our vast universe. The swirling motion of stars and cosmic dust, the vibrant colors, and the immense scale all evoke a sense of mystery and wonder. Galaxies are both elegant and complex, embodying the balance between chaos and order. This duality inspired me to explore patterns and shapes that reflect the beauty and unpredictability of the cosmos. Through this project, I aimed to capture the essence of the galaxy’s mesmerizing movement and its delicate balance of simplicity and complexity.

In my code, I implemented two key features. The first was the required assessment of movement and acceleration. By pressing the up and down arrow keys, the speed of the particles could be controlled, allowing for a dynamic interaction with the animation. The second feature involved particle interaction through hovering. As the cursor hovers over the particles, they would disperse, creating a sense of disruption and fluid motion in response to user input.

Dark Matter May Not Exist: These Physicists Favor of a New Theory of Gravity

Highlight I’m proud of

Here I was able to create a special class for the particles.

class Particle {
  constructor(vx, vy) {
    this.vx = vx;
    this.vy = vy;
    this.num = 255;
    this.a = 255;
    this.loc = createVector(width / 2, height / 2);  // Start from the center
    this.vel = createVector(0, 0);  
    this.acc = createVector(1, 1);
  }

  update() {
    // Apply acceleration using the acceleration factor
    this.vel.add(this.acc.mult(accelerationFactor));  
    this.loc.add(this.vel);

    // Reset acceleration and limit the velocity for smoother control
    this.acc.mult(0);
    this.vel.limit(0.5);  
  }

  repulse() {
    // Calculate the distance between the particle and the mouse
    let mouse = createVector(mouseX, mouseY);
    let dir = p5.Vector.sub(this.loc, mouse);  
    let distance = dir.mag();  

    if (distance < repulsionRadius) {  // If the particle is within the repulsion radius
      dir.normalize();  // Normalize the direction to get just the direction vector
      let force = map(distance, 0, repulsionRadius, 5, 0);  // Stronger repulsion the closer the particle is
      dir.mult(force);  // Multiply the direction vector by the repulsion force
      this.vel.add(dir);  // Apply the repulsion force to the particle's velocity
    }
  }

  isOutside() {
    // Check if the particle goes outside the canvas
    return (this.loc.x < 0 || this.loc.x > width || this.loc.y < 0 || this.loc.y > height);
  }

  display() {
    // Update acceleration based on the particle's properties and a trigonometric function for spirals
    this.acc = createVector(
      sin(radians(this.vx + this.num / 2)) / 2,
      cos(radians(this.vy - this.num / 2)) / 2
    );

    // Draw the particle with a fade effect
    fill(255, this.a);
    var r = map(this.a, 255, 0, 1, 10);  // Particle size changes as it fades
    ellipse(this.loc.x, this.loc.y, r);

    this.num += map(this.a, 255, 0, 1, 0);  // Update num for smooth spiral motion
    this.a -= 0.1;  // Gradually reduce alpha for a fade-out effect
  }
}

Embedded sketch

Sketch:
 https://editor.p5js.org/mariamalkhoori/sketches/_t5yMvlGp
Reflection and ideas for future work or improvements
  • User Interaction: Add interaction features such as particles reacting to clicks or drag-and-drop functionality.
  • Different Particle Types: Introduce various particle types with distinct behaviors, such as different shapes or sizes.
  • Customizable Motion Patterns: Allow particles to follow different patterns or trajectories, like zig-zags or chaotic paths.
Refrences:
  • https://editor.p5js.org/RonanChang/sketches/S1NQJgbx4
  • https://decodingnature.nyuadim.com/2024/08/28/week-1-fireflies-by-dachi/

 

Week 2 – Rain

Your concept:

Rain always brings me peace; therefore, for this project, I created a scene of rainfall to reflect the feeling I get when it rains. I had some ideas before I settled into this one, such as sunset and sunrise, moving waves, and birds. However, replicating rainfall spoke to me the most. 

I began this assignment by reviewing the materials for this week and watching inspirational videos of things that move. Then, I read a little about the physics behind rainfall, its average acceleration relative to its size, and velocity. I had to do some conversions and basic math to make it logical on a computer screen. For the scene, I used a PNG image for the mountains, a gradient for the sky, rain audio, and some stars to enhance the theme.

Highlight of code:

I tried to make my code neat and clean for this project by creating a different class file and functions whenever possible. The most challenging part of this project was figuring out logical numbers for the line length, acceleration, and velocity so that the rain looks similar to real life. I also had some trouble figuring out how to make sure the lines were straight and not move in any other direction, so I also experimented with it.

class RainDrop {
  constructor(x, y) {
    this.position = createVector(x, y);
    // make the numbers more logical when it comes to rain in pixcels
    this.velocity = createVector(0, random(0.6, 0.9));
    this.acceleration = createVector(0.001, 0.9);
    this.length = random(10, 20);
    this.Colorstrength = random(20, 255); //form od depth
  }
  show() {
    stroke(200, this.Colorstrength);
    //     subtracting x from the length to create a vertical line if i dont it looks weird
    line(
      this.position.x,
      this.position.y,
      this.position.x,
      this.position.y - this.length
    );
  }

  update() {
    this.velocity.add(this.acceleration);
    this.position.add(this.velocity);
  }
}

 

Embedded sketch:

Future work:

While this project satisfies what I have learned so far, in the future, I want to add other factors that affect the acceleration of a raindrop, like the force of air and its density. I also want to add more depth so that the sketch resembles real life and to enhance the experience. Furthermore, I want to loop the sound and create a button for the user to have the power to play and stop the audio.

Resources:

https://hypertextbook.com/facts/2007/EvanKaplan.shtml#:~:text=When%20a%20raindrop%20falls%20to,as%20would%20any%20falling%20body.

https://hypertextbook.com/facts/2007/EvanKaplan.shtml#:~:text=When%20a%20raindrop%20falls%20to,as%20would%20any%20falling%20body.

https://p5js.org/reference/p5.Element/show/

https://p5js.org/reference/p5/lerpColor/

 

Week 2, Palm Date Trees

Since it is around the end of the dates season in the UAE, I have decided to do this assignment related to that. Upon clicking the down arrow button, you can witness the dates falling from the palm trees in a constant acceleration.

It was quite difficult for me to find a video, so here is a photo of date palm trees instead:

The UAE is sending dates into space | Esquire Middle East – The Region's Best Men's Magazine

I limited the acceleration to 3 as I did not want it to speed up too fast as it would seem to be unrealistic. Below is the part of code that shows the dates accelerating when the down arrow button is pressed.

 if (keyCode === DOWN_ARROW) {
  dates.acceleration.y = 0.01;
  dates2.acceleration.y = 0.01;
  dates3.acceleration.y = 0.01;
}

For future improvements, I would allow the user to restart it by clicking the mouse or a button. I also would add different kinds of dates and more of them.

 

Week #2 – Some birds and a tree

Introduction

To get inspired for this week assignment, I took a walk around the campus. I had many ideas in my mind about what I wanted to do; some of them were about trying to imitate the movement of ants or the light of the sun. Although, something caught my interested when I stumbled upon this view:

That is when I realized what I wanted to do.

The Concept

Once I observed this tree populated by many birds, I wanted to recreate both the movement of the leaves, of the tree, and the path the birds take to reach it. At first, I was intimidated to think about this, since it would be very hard to simulate a tree with moving leaves. Nevertheless, I was intrigued.

To reach a satisfactory conclusion for the project, first I had to make a quick sketch about what I wanted to do:

Mockup
Figure 1. Mock-up of the moving trees and how they are going to move according to region.

From what I analyzed in this sketch, I would have to do the following:

    • Simulate many leaves moving at the same time without lagging the computer.
    • Make a believable movement using velocity and acceleration.
    • Populate, randomly, each region and with a different pattern (that is, how they are going to generate according to the range specified).
    • Understand how the birds will interact after the leaves are populated.

Preparing the scenario

Compared to last week’s assignment, I felt that it was too abstract and needed a bit more of style in order to be more presentable. From this experience, I wanted to avoid what I did previously and improve upon it, thus, I wanted to develop a more “alive” canvas.

For this, I needed to create first the scenario that was in symphony with my then progress done:

Figure 2. Preparing the scenario.

Not only that, but in order to create this “alive” canvas, I also realized we would need audio. So, I extracted the audio from the video I recorded, edited it and then added it to the project:

Figure 3. Preparing the background audio.

The code

According to what we have seen in class at the moment, for this code it was essential to work with vectors. Essentially, the vectors were used for almost everything: The ranges where the leaves spawn, the leaves and the birds.

In order to understand how this is possible, here is a quick explanation of how it works in a sequential order:

    1. Regions are created, manually, with the help of createVector(x,y). These regions are stored in the class Leaves. The reasoning of creating regions is to simulate, as accurate a possible with the limitations of p5.js, the movement of the leaves without creating lag and with enough diversity to create the illusion.
    2. After the regions are set, the leaves now start to spawn in each region. There are a total of 5 different regions and, by default, 80 leaves by group. The leaves themselves are represented by green circles that walk through transparency with the help of the Perlin movement. Not only that, but the leaves move by accelerating forwards and backwards in their region.
    3. After the regions and leaves are spawned, the birds can start appearing. To avoid creating a lot of circles in the screen, I decided to only draw one black circle for the birds. They will appear one by one from either the left or right part of the screen. The bird will select a region, randomly, as the endpoint. As mentioned, the birds are represented as black circles that will appear as medium-sized and will be further decreasing to create the illusion of the bird going inside the tree. Once the size of the bird reaches 0, it will generate another bird.

Important note: In order to simulate all of this believably, I had to lock the frame rate to 10. Since if it left with a default of 60, it will look that the leaves and birds are moving at super speeds.

What I am mostly proud of

I am proud that I could simulate how leaves move (at least partially). This was the most challenging part of this work and the one that needed to be addressed first. I took some examples from the class in order to understand how to create this movement. Although, sometimes due to not understanding how it fully worked, the leaves would go out of the Canva, move weirdly, extremely fast and unnatural or just not show at all (because they were going so fast that our eyes could not perceive the moment it left the screen).

Here is a quick example of the code that I used for the movement of the leaves:

// ----- Move leaves according to region. -----

        for (let i=0; i<amount_of_leaves; i++){
            //Taken from the example taught in class.
            let dir = p5.Vector.sub(this.range1, this.p1_leaves[i]);

            dir.normalize();
            dir.mult(0.05);

            this.acceleration = dir;
            this.velocity.add(this.acceleration);
            this.velocity.limit(5);
            this.p1_leaves[i].add(this.velocity);
        }


        for (let i=0; i<amount_of_leaves; i++){
            //Taken from the example taught in class.
            let dir = p5.Vector.sub(this.range2, this.p2_leaves[i]);

            dir.normalize();
            dir.mult(0.05);

            this.acceleration = dir;
            this.velocity.add(this.acceleration);
            this.velocity.limit(5);
            this.p2_leaves[i].add(this.velocity);
        }

        
        for (let i=0; i<amount_of_leaves; i++){
            //Taken from the example taught in class.
            let dir = p5.Vector.sub(this.range3, this.p3_leaves[i]);

            dir.normalize();
            dir.mult(0.05);
 
            this.acceleration = dir;
            this.velocity.add(this.acceleration);
            this.velocity.limit(5);
            this.p3_leaves[i].add(this.velocity);
        }

Although, I am not very proud by the amount of for statements…

Similarly, for the movement of the birds the code was similar, but easier to understand since I knew how it worked:

fly(rng_number){
      //Decide if the bird on the left or right will flight. After that, decide on the final destination to then apply the motion.
        if (rng_number == 1){
            if (this.final_region_destination == 1){
                this.dir = p5.Vector.sub(leaves.range1, this.bird1);
            } else if (this.final_region_destination == 2){
                this.dir = p5.Vector.sub(leaves.range2, this.bird1);
            } else if (this.final_region_destination == 3){
                this.dir = p5.Vector.sub(leaves.range3, this.bird1);
            } else if (this.final_region_destination == 4){
                this.dir = p5.Vector.sub(leaves.range4, this.bird1);
            }
            
            this.dir.normalize();
            this.dir.mult(0.6);

            this.acceleration = this.dir;
            this.velocity.add(this.acceleration);
            this.velocity.limit(10);
            this.bird1.add(this.velocity);

            if (this.t <= 0){
                this.restart();
            }

        }

        else if (rng_number == 2){
            if (this.final_region_destination == 1){
                this.dir = p5.Vector.sub(leaves.range1, this.bird2);
            } else if (this.final_region_destination == 2){
                this.dir = p5.Vector.sub(leaves.range2, this.bird2);
            } else if (this.final_region_destination == 3){
                this.dir = p5.Vector.sub(leaves.range3, this.bird2);
            } else if (this.final_region_destination == 4){
                this.dir = p5.Vector.sub(leaves.range4, this.bird2);
            }
            
            this.dir.normalize();
            this.dir.mult(0.6);

            this.acceleration = this.dir;
            this.velocity.add(this.acceleration);
            this.velocity.limit(10);
            this.bird2.add(this.velocity);

            if (this.t <= 0){
                this.restart();
            }

        }

Again, not very proud with how copied and pasted it looks…

The Sketch

So, after all of this explanation, what is the final product? Well, there is the final sketch.

Note: The “white background effect” is intentional. Also, this Canva has background audio, no mouse interactions and a default of 10 frames per second.

Full-screen version: Go to the Full-screen version

Reflection and future improvements

I am mostly happy to how this assignment concluded. I feel that I learned new things about the programming world as well as how to interpret movements in nature. Although, there are some improvements I want to make for future works:

    • Even though this sounds nonsensical, I would like to avoid using too many in-class examples for my codes and challenged myself a bit more with what I can find out of the box.
    • Avoid that the circles accumulate all together if the Canva is left running for a few minutes.

Credits

Some references I used for help are the following:

FrameRate reference: https://p5js.org/reference/p5/frameRate/

Sound reference: http://p5js.org/reference/#/p5.SoundFile

 

And the external programs I used are:

To create the background: GIMP.

To prepare the audio: Audacity.

Week 2 – Khalifa Alshamsi

Concept:

My concept goes back to Dory from Finding Nemo. She swims around and tries to find Nemo, but she will never find him in this universe I created. With a constant restart whenever she goes off the screen.

Code:

let fish; // Declaring a variable for the fish object

function setup() {
  createCanvas(600, 400); 
  fish = new Fish(); // Initializes the fish object
}

function draw() {
  background(0, 150, 255); // Ocean blue background for a feeling of thr sea
  fish.update(); // Updates the fish's position and movement
  fish.display(); // Display the fish on the canvas
}

class Fish {
  constructor() {
    // Initialize the fish's properties: position, velocity, and acceleration
    this.position = createVector(width / 2, height / 2); // Starts the fish in the middle of the canvas
    this.velocity = createVector(2, 0); // Give the fish an initial velocity to move it to the right
    this.acceleration = createVector(0.01, 0); // Adds a small acceleration to simulate swimming
    this.angle = 0; // Angle for tail movement
  }

  update() {
    // This function updates the fish's position and behavior each frame

    // Simulate natural swimming by adding small random changes to the fish's acceleration
    this.acceleration = createVector(random(-0.01, 0.01), random(-0.01, 0.01));
    
    // Add the acceleration to the velocity to change the fish's speed
    this.velocity.add(this.acceleration);

    // Limits the maximum speed of the fish to make the movement smoother
    this.velocity.limit(3);

    // Updates the fish's position by adding the velocity to it
    this.position.add(this.velocity);

    // If the fish moves off one edge of the canvas, make it reappear on the opposite edge
    if (this.position.x > width) this.position.x = 0; // Reappear on left side if off right
    if (this.position.x < 0) this.position.x = width; // Reappear on right side if off left
    if (this.position.y > height) this.position.y = 0; // Reappear on top if off bottom
    if (this.position.y < 0) this.position.y = height; // Reappear on bottom if off top

    // Creates an oscillating angle for the fish's tail using the sine function
    // The angle swings back and forth, making the tail move naturally
    this.angle = sin(frameCount * 0.1) * PI / 6;
  }

  display() {
    // This function draws the fish on the canvas

    // Set the fill color to blue for Dory's body
    fill(0, 100, 255); // Blue body color
    stroke(0); // Black outlines
    strokeWeight(1); // Set the line thickness for the outline

    push(); // Starts a new drawing state to control the position and rotation of the fish
    translate(this.position.x, this.position.y); // Moves the fish to its current position
    rotate(this.velocity.heading()); // Rotates the fish in the direction of its movement

    // Draws the fish's body as an ellipse
    ellipse(0, 0, 50, 20); // The fish's body (50 pixels wide, 20 pixels tall)

    // Draws the fish's tail as a triangle that moves back and forth
    // Move the tail to the back of the body and rotate it based on the oscillating angle
    push(); // Starts a new drawing state for the tail
    translate(-25, 0); // Moves the tail to the back end of the fish
    rotate(this.angle); // Rotates the tail back and forth
    fill(255, 215, 0); // Yellow color for Dory's tail
    triangle(0, -10, -20, 0, 0, 10); // Draw the tail as a triangle
    pop(); // Restore the previous drawing state for the body

    // Draw Dory's fins (small yellow triangles)
    fill(255, 215, 0); // Yellow fin color
    triangle(10, -10, 20, 0, 10, 10); // Top fin
    triangle(0, 5, -10, 10, -5, 5);   // Bottom fin

    // Draw black markings on the body
    fill(0); // Black for markings
    beginShape(); // Start shape for the black marking
    vertex(0, -10);
    vertex(10, -5);
    vertex(0, 5);
    vertex(-10, 0);
    endShape(CLOSE); // Create a simple black marking shape

    // Draws the fish's eye as a small white circle with a black pupil
    fill(255); // White for the eye
    ellipse(15, -5, 8, 8); // Draw the eye (8x8 pixel circle)
    fill(0); // Black pupil
    ellipse(15, -5, 4, 4); // Draw the pupil (4x4 pixel circle)

    pop(); // Restores the previous drawing state
  }
}

In this simulation, the fish moves by updating its position based on velocity and acceleration, which makes its motion feel natural and fluid, like a real fish swimming. The velocity determines how fast and in which direction the fish swims, while the acceleration adds subtle variations, simulating the fish’s changing speed and slight adjustments in its path. Creating a decent-looking fish was tricky because I had to balance the simplicity of shapes (an ellipse for the body, triangles for the tail, and fins) while ensuring it still resembled a fish, particularly Dory from Finding Nemo. I also added some black markings and a wiggling tail to make the movement more realistic.

One fun complication was ensuring the fish didn’t just swim off the canvas and disappear forever.

// If the fish moves off one edge of the canvas, make it reappear on the opposite edge
if (this.position.x > width) this.position.x = 0; // Reappear on the left side if off the right edge
if (this.position.x < 0) this.position.x = width; // Reappear on the right side if off the left edge
if (this.position.y > height) this.position.y = 0; // Reappear at the top if off the bottom edge
if (this.position.y < 0) this.position.y = height; // Reappear at the bottom if off the top edge

Horizontal boundaries:

If the fish’s x position goes beyond the right edge (this.position.x > width), it reappears at the left edge by setting this.position.x = 0.
Similarly, if it swims past the left edge (this.position.x < 0), it reappears on the right by setting this.position.x = width.

Vertical boundaries:

If the fish swims off the bottom (this.position.y > height), it reappears at the top by setting this.position.y = 0.
If it goes above the top (this.position.y < 0), it reappears at the bottom by setting this.position.y = height.

This wrapping behavior is achieved by checking if the fish’s position exceeds the canvas boundaries and resetting its position to the opposite side, ensuring Dory never swims too far away!

Sketch:

Reflection:

I would love to know more about how to create better-looking shapes without that much struggle; while the end results look like fish, they aren’t the best out there. Also, I would like to add a little controller to make the fish move around.

Resources:

  • https://p5js.org/reference/p5/p5.Vector/
  • https://p5js.org/reference/p5/sin/
  • https://p5js.org/reference/p5/frameCount/#:~:text=A%20Number%20variable%20that%20tracks,in%20draw()%20finishes%20executing.
  • https://forum.processing.org/two/discussion/16493/daniel-shiffman-s-nature-of-code-exercise-1-5.html

Week 2 – Assignment

The Concept

The concept for this project was to create a rain simulation with lightning. Rain is not something we experience here usually but we can simulate it. I don’t have a specific video or picture in mind; I just went to p5 to simulate raindrops, ripples, and lightning.

Code Highlight

function generateLightningBolt() {
lightningBolt = [];
let x = random(width * 0.25, width * 0.75);
let y = 0;
lightningBolt.push(createVector(x, y));
for (let i = 0; i < 8; i++) {
x += random(-30, 30);
y += random(30, 60);
lightningBolt.push(createVector(x, y));
}
}
function drawLightningBolt() {
stroke(200, 200, 255);
strokeWeight(4);
noFill();
beginShape();
for (let i = 0; i < lightningBolt.length; i++) {
vertex(lightningBolt[i].x, lightningBolt[i].y);
}
endShape();
}
function drawSparkles() {
noStroke();
for (let i = 0; i < 20; i++) {
let sparkleX = lightningBolt[lightningBolt.length - 1].x + random(-40, 40);
let sparkleY = lightningBolt[lightningBolt.length - 1].y + random(-40, 40);
fill(255, 255, 255, random(150, 255));
ellipse(sparkleX, sparkleY, random(3, 8), random(3, 8));
}
}

The part of the code that I’m proud of is the lighting. The lighting has two elements, the bolt and the sparkles. For the bolt, I created a random vector starting from a random position at the top of the screen and started adding random values from fixed intervals to that random vector’s coordinates to get the next subsequent random vectors for the zigzag-like pattern of the lighting bolt. Finally, I plotted those vectors by converting each point to a vertex and using the begin and end shape functions to connect those vertices. For the sparkles, I used 20 ellipses the last vertex of the lightning bolt. Each ellipse has a random major and minor axis length fixed between two values.

Sketch

Future Improvements and Reflection

The simulation is a basic representation of rain with a thunderstorm. However, adding sound might make the experience full and realistic. The sounds are mainly for the rain, ripples, and thunder.

Week 2 – Assignment

Concept:

For this week’s assigment, I have decided to get inspired by my favorite season: WINTER (kind of ironic giving the fact that we live in Abu Dhabi). I found myself reminiscing about the snowflakes that I get to see outside my window every time I go back home.

I found this YouTube video for inspiration:

After working for a bit on it, this was the final result:

This is the code:

//SNOWFLAKES ASSIGNMENT 2
//by SP

let snowflakes = [];
let panePadding = 20;

function setup() {
  createCanvas(400, 400);
  noStroke();
}

function draw() {
  setGradient(0, 0, width, height, color(20, 29, 68), color(100, 150, 255));

  // new snowflakes
  let t = frameCount / 60;
  if (random() < 0.05) {
    snowflakes.push(new Snowflake());
  }

  for (let flake of snowflakes) {
    flake.update(t);
    flake.display();
  }

  // remove snowflakes that are off the screen
  snowflakes = snowflakes.filter((flake) => !flake.offScreen());

  drawWindowFrame();
}

class Snowflake {
  constructor() {
    this.posX = random(width);
    this.posY = random(-50, 0); // start slightly off-screen
    this.size = random(5, 12); // size of the snowflake
    this.speed = random(1, 3); // falling speed
    this.drift = random(-0.5, 0.5); // slight drift left or right
    this.angle = random(TWO_PI); // random rotation angle
    this.rotationSpeed = random(-0.01, 0.01); // slight rotation
  }

  update(time) {
    this.posY += this.speed;
    this.posX += this.drift;
    this.angle += this.rotationSpeed;
  }

  display() {
    push();
    translate(this.posX, this.posY);
    rotate(this.angle);
    drawSnowflake(this.size);
    pop();
  }

  offScreen() {
    return this.posY > height;
  }
}

function drawSnowflake(size) {
  stroke(255);
  strokeWeight(2);
  noFill();

  // star-like shapes with lines to represent a snowflakes
  beginShape();
  for (let i = 0; i < 6; i++) {
    let x = cos((TWO_PI * i) / 6) * size;
    let y = sin((TWO_PI * i) / 6) * size;
    line(0, 0, x, y);

    // small branches for each main line
    for (let j = 0.4; j < 1; j += 0.4) {
      let branchX = cos((TWO_PI * i) / 6) * size * j;
      let branchY = sin((TWO_PI * i) / 6) * size * j;
      line(
        branchX,
        branchY,
        branchX + cos((TWO_PI * (i + 0.5)) / 6) * size * 0.2,
        branchY + sin((TWO_PI * (i + 0.5)) / 6) * size * 0.2
      );
      line(
        branchX,
        branchY,
        branchX + cos((TWO_PI * (i - 0.5)) / 6) * size * 0.2,
        branchY + sin((TWO_PI * (i - 0.5)) / 6) * size * 0.2
      );
    }
  }
  endShape(CLOSE);
}

// a vertical gradient
function setGradient(x, y, w, h, c1, c2) {
  for (let i = y; i <= y + h; i++) {
    let inter = map(i, y, y + h, 0, 1);
    let c = lerpColor(c1, c2, inter);
    stroke(c);
    line(x, i, x + w, i);
  }
}

// draw the window frame
function drawWindowFrame() {
  fill(80, 60, 40);
  noStroke();

  let paneWidth = (width - panePadding * 3) / 2;
  let paneHeight = (height - panePadding * 3) / 2;

  rect(0, height / 2 - panePadding / 2, width, panePadding);
  rect(width / 2 - panePadding / 2, 0, panePadding, height);

  rect(0, 0, panePadding, height); // left
  rect(width - panePadding, 0, panePadding, height); // right
  rect(0, 0, width, panePadding); // top
  rect(0, height - panePadding, width, panePadding); // bottom
}

The code that I am most proud of is the one for the snowflakes. In the beginning, I just created small circles but then I decided to make them look more realistic. It took me a long time but it was worth it because it all worked out in the end.

Reflection and ideas for future work or improvements:

Overall, I think I did a good job. Of course it is not super realistic but we are slowly getting there. For the future, I would like to recreate the entire scene and add a table next to the window.

Week 2- Pigeon Feeding Simulation

Concept:
In this assignment, I created an interactive scene where pigeons wander around a gray ground (representing something like a park or city square) searching for food. I added two trees on either side of the canvas, and when I click on them, leaves fall and disappear once they hit the ground. The pigeons move toward randomly placed food, and after one of them reaches the food, a new piece of food appears in a different spot. The goal was to simulate natural pigeon behavior and add a fun, interactive element with the falling leaves, all while using vector-based physics to bring the motion to life.

Code Highlight:
One part of the code I’m really happy with is the falling leaves interaction:

function mousePressed() {
  for (let i = 0; i < treePositions.length; i++) {
    let treePos = treePositions[i];
    // Check if the mouse click is within the tree's area
    if (dist(mouseX, mouseY, treePos.x, treePos.y) < 75) {
      // Generate falling leaves from the clicked tree
      for (let j = 0; j < 10; j++) {
        leaves.push({
          position: createVector(treePos.x + random(-20, 20), treePos.y),
          velocity: createVector(random(-1, 1), random(1, 3)) // Falling leaves
        });
      }
    }
  }
}

This part of the code is what handles the falling leaves when you click on a tree. When the user clicks near one of the trees the code checks if the click is within range using the dist() function to measure distance. If it is it triggers a loop that generates 10 leaves each with random positions and velocities so they fall in a natural way. The leaves then get added to an array so they can be drawn and moved across the screen.

I’m really proud of this because it was the part I struggled with the most. Figuring out how to create that random natural-looking motion for the leaves and getting the click interaction to work properly took some effort but it adds a lot of life to the scene!

Embedded Sketch: 


Reflection and Ideas for Future Work:
Looking back, I’m really happy with how the pigeons’ movement and the interactive leaves turned out. It’s a fun and dynamic scene, but I have a few ideas for improvements and future work:

Perlin Noise for the Ground: I want to add Perlin noise to the ground to give it texture, making it look like dirt or pavement instead of just flat gray.

More Realistic Pigeon Behavior: I’d like to implement flocking behavior so the pigeons move together in a more natural way, like real pigeons do.

Tree Sway and Better Leaves: I think it would be cool to make the trees sway slightly when the leaves fall and vary the size and speed of the leaves for more realism.

Animated Pigeons: Adding animations for the pigeons, like walking or pecking, would make them feel more alive.