Coding Assignment – Week #2 – The Buzzing Bee

For this weeks assignment, I decided to go with a bee’s movement as I was inspired by the flies around campus annoying me around the palms but wanted something a bit cuter. I wanted to make sure the bee’s movement wasn’t smooth and a bit static. I also want to incorporate images in my second IM. project so learnt how to handle images. The following is a bee video of the inspiration.

https://www.youtube.com/watch?v=-d_pQ3DyzHg

This was my initial code but it made the bee images simply move smoothly.

class Bee 
{
  constructor(x, y) 
  {
    this.position = createVector(x, y);
    this.velocity = createVector(random(-0.65, 0.5), random(-0.75, 0.5));
    this.acceleration = createVector(0, 0);  
    this.img = bee_img;
  }

  update() {
    
    this.acceleration.limit(3);

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

I added some additional behaviours and randomness, alongside a ‘slow down’ vector to have the acceleration decrease whenever the acceleration was a bit too high.

constructor(x, y) 
  {
    this.position = createVector(x, y);                  //positioning of the bee
    this.velocity = createVector(random(-0.65, 0.5), random(-0.75, 0.5));          
    this.acceleration = createVector(0, 0);               // start acceleration 0
    this.personality = random(-0.1, 0.25);       // random multiplier
    this.slow_down = createVector(-1.5,-1);      //for when the bee comes close to y-borders
    this.img = bee_img;
  } 

  update() 
  {
    let randomForce = createVector(random(-5, 5), random(-5, 5));//even chnace
    randomForce.mult(this.personality);
    this.acceleration.add(randomForce);
    
    this.acceleration.limit(3);        //no faster than 3

    this.velocity.add(this.acceleration);
    this.position.add(this.velocity);

    this.velocity.mult(random(0.55,0.65));      //slow down as a way of showing air       resistance
    
    
    if (this.position.x > width) this.position.x = 0;
    if (this.position.x < 0) this.position.x = width;
    if (this.position.y > 350) this.position.y -= 150;      //if hits top/bottom borders
    if (this.position.y < 50) this.position.y += 150;
    if(this.acceleration.x > 2.6)                            //if acceleration too high
    {
      this.acceleration.add(this.slow_down);
    }
  }

 

I also had some problems when it came to uploading images from the URL so I learnt how to get it from GitHub making sure it would always work on any device.

What would I do differently next time?

I want to try and add some more insects and items in nature that attract bees like honey so that there is a chance the bee will buzz around a certain area.
>
My final code

https://editor.p5js.org/kk4827/full/1Mx0g_u9n

Assignment Week #2

Concept:

This week’s assignment represents water droplets falling on the ground. They are visually represented as ellipses and they exhibit natural falling and splashing behavior.

It is inspired by the following slow-motion video:

Demo:

Code: https://editor.p5js.org/bdr/sketches/YS6DBtNOH

Process:

https://imgur.com/WlcV5ZmCode Walkthrough:

Drop Class:

Constructor: The constructor initializes a new water drop object with the following properties:
– Position: A 2D vector representing the initial position of the raindrop on the canvas. It is set to a random location within the boundaries.
– Velocity: A 2D vector representing the initial velocity of the raindrop. It starts with no horizontal velocity and a downward velocity of 5 pixels per frame.
– Acceleration: A 2D vector representing the acceleration of the raindrop. It starts with no horizontal acceleration and a vertical acceleration of 0.2 pixels per frame.
– Length: The length of the water drop, which is a random value between 10 and  20 pixels.
r: Control the size of the splash.
Opacity: Set a smooth transition for the splash.
Landed: A boolean variable to indicate whether the water drop landed on the ground.

Methods:
Update(): Update the water drop’s position based on the velocity and acceleration. It also limits the raindrop to a certain velocity.
Display(): Draw the drop on the canvas as an ellipse. The color is white with an opacity of 120. When landed, its length is gradually reduced to create a disappearing effect.
Land(): Display a landing effect. It is a shrinking ellipse with decreasing opacity.

Setup(): Create the canvas 640×640, and initialize an array of water drops (40 droplets).

Draw(): Call the object’s methods, and replace the drops that have landed with a new one creating a continuous simulation.

Challenges:

One of the challenges is certainly creating the perfect splashing effect, it took some trial and error before landing on the ideal parameters.

Improvements:

– Add water splash sound.
– Allow the user to control where the drops are originating from using mouseX and mouseY.

Assignment Week #2 – FROG

Concept:

This assignment revolves around an interactive frog and fly simulation. In this sketch, the player can click on the canvas to spawn a fly which the frog will eat extending its tongue to catch it. The primary objective is to create an experience that simulates the movements of a fly and a frog.

Sketch:

https://editor.p5js.org/mi1171/full/aMpw5OAKN

Code:

function draw() {
  background(220);

  food.show();
  food.update();
  // Update and display the tongue
  if (choice == 1) {
    if (food && !food.isEaten) {
      food.show(); // Display the food
      if (
        tongueLength <
        dist(
          player.position.x,
          player.position.y,
          food.position.x,
          food.position.y
        )
      ) {
        player.extendTongue(); // Call the extendTongue method of the Player class
      } else if (
        tongueLength > 0 &&
        tongueLength >=
          dist(
            player.position.x,
            player.position.y,
            food.position.x,
            food.position.y
          )
      ) {
        food.isCaught = true;
        player.retractTongue(); // Call the retractTongue method of the Player class
      }

      // Check for collision between player and food
      if (
        dist(
          player.position.x,
          player.position.y,
          food.position.x,
          food.position.y
        ) <
        player.radius + food.radius
      ) {
        food.isEaten = true; // Food is eaten
        food.isCaught = false;

        tongueLength = 0; // Retract the tongue when food is eaten
        choice = 0;
      }
    }
  }
  player.update();
  player.show();

  if (millis() > nextJumpTime) {
    bool = random(0, 10);
    if (bool > 2) {
      player.randomJump();
    } else {
      choice = 1;
    }
    setNextJumpTime();
  }
}

 

This block of code is the main logic behind the frog’s behavior. It continuously updates and displays the positions of the frog and the food item on the canvas. The game logic includes extending the frog’s tongue towards the food, retracting the tongue when the food is caught, and marking the food as eaten. In addition, the random jumping and tongue extensions, are controlled based on random chance combined with time intervals.  The frog has a 20 percent chance of extending its tongue and an 80 percent chance of randomly jumping.

Challenges:

During the development of this frog game, several intriguing challenges were encountered:

Collision Detection: Implementing accurate collision detection algorithms to determine when the frog’s tongue makes contact with food.

Random frog/fly Movements: To create a somewhat realistic experience, the frogs’s random jumping behavior had to be balanced carefully along with the fly’s erratic movements. Random vectors were employed to determine both vertical and horizontal velocities.

Future Improvements:

Looking ahead, there are several exciting possibilities for enhancing and expanding upon this interactive frog game:

Additional animals: Incorporate multiple animals to simulate a full ecosystem.

Audio Enhancements: Elevate the gaming experience by adding sound effects for jumping, food catches, and background music.

Coding Assignment Week #2 – Sand Much?

INSPIRATION

Last week I went to the outer Falcon field for my cricket practice and saw sand being pushed aside, and thrown into the air as people walked. I decided to take a closer look and base this week’s coding assignment on this nature of sand flying in the air. Here is a video of what it looked like. I was unable to get a good video of the sand flying in the air (it was so thin and dispersed that it barely showed in the video), so I uploaded one taken from the internet:

CONCEPT

The concept of my assignment this week is to have sand particles initially at the bottom of the screen, and then depending on the movement of the mouse, apply acceleration to the sand particles to have them appear as if flying in the air. I also added a bit of gravitational acceleration to the sand particles to make the simulation more realistic and have the particles settle down after a while.

MOOD BOARD

Before I started coding, I prepared a mood board for my project. This gave me clarity on the vision I was trying to build towards.

CODE & WORKING VIDEO

I have to admit it was pretty hard to code it and I struggled to model the behaviour accurately. After many failed attempts and tweaking the parameters of particle acceleration and gravity, I could get something close to what I observed.

Here are the various attempts and outputs I got:

For the code part, I built on the mover class sketch we saw in class – having the circle accelerate in the direction of the mouse. I used that as a skeleton for my program and added other features/variables and components to make it more complex and achieve the desired results.

class Particle {
  constructor() {
    let x = randomGaussian(width/2,100); // to have all particles near the center and close to ground initially
    let y = random(height-20, height);
    this.position = createVector(x, y);
    this.velocity = createVector(0, 0);
    this.acceleration = createVector(0, 0);
    this.gravity = createVector(0, 0);
    this.netAcc = createVector(0, 0); // sum of particle acceleration and gravity
    this.scaleFactor = random(0.01); // scale the acc by what factor?
  }

  update() {
  
  let mouse = createVector(mouseX, mouseY);

  // compute direction of acc
  let dir = p5.Vector.sub(mouse, this.position);
  dir.normalize(); // normalize
  dir.mult(-1*this.scaleFactor); // scale

  // accelerate only if mouse is in Screen
  if (mouseX < width && mouseX > 0 && mouseY > 0) {
    this.acceleration = dir;
    this.gravity = createVector(0,0.005);
    this.centerGravity = createVector(0,0.001);
    this.netAcc = p5.Vector.add(this.acceleration, this.gravity);
    this.velocity.add(this.netAcc);
    this.velocity.limit(5);
    this.position.add(this.velocity);
  }
    else {
      // print(this.acceleration);
      if (this.acceleration != 0) { // change acceleration direction to have particles come back
        this.acceleration.x *= -1;
        this.acceleration.y *= -1; 
      }
    }
  constrain(this.position.y, 0, height);
}

  display() {
    push()
    stroke(225,191,146);
    strokeWeight(2);
    fill(127);
    ellipse(this.position.x, this.position.y, 2, 2);
    pop();
  }

  checkEdges() {
    if (this.position.x > width) {
      this.position.x = 0;
    } else if (this.position.x < 0) {
      this.position.x = width;
    }

    if (this.position.y > height) {
      this.position.y = height;
      this.acceleration = 0;
    } else if (this.position.y < 0) {
      this.position.y = height;
      // this.acceleration.y *= -1;
    }
  }
}
let particles = []; // array to strore all sand particles
let num = 1000; // number of particles in the system

function setup() {
  // background(51);
  createCanvas(400, 400);
  for (let i = 0; i < num; i++)
    particles[i] = new Particle(); //populate particle array
}

function draw() {
  
  background(189,246,254);
  
  for (let i = 0; i < num; i++) {
    particles[i].update();
    particles[i].checkEdges();
    particles[i].display();
  }
}

P5 SKETCH

https://editor.p5js.org/shreyagoel81601/sketches/luBPK9fMi

FUTURE WORK AND IMPROVEMENTS

There is a lot that could be improved in this project. While it is close to stimulating sand flying in the air, it is not completely accurate. It is because once the sand particles go up in air, they must come down (at a faster rate than what it is right now), and that cannot be achieved only by acceleration. We will have to play a bit with forces there. We could also add wind direction and air resistance to make it more realistic. Also, currently, the acceleration keeps increasing and we move the mouse, but that is not a real-life scenario. If someone walks past the sand or kicks it, the force is momentous and not ongoing. So this also could be improved once we learn about forces and modelling that.

Xiaozao Coding Assignment #2

Create your Planet System

Source code: https://editor.p5js.org/Xiaozao/sketches/55EaOIHQ9

Reference: The Coding Train https://thecodingtrain.com/learning/nature-of-code/2.5-gravitational-attraction.html

Part 1: Concept

The movement of objects that I found in nature was the solar system.

It’s amazing to discover how the sun and the planets interact with each other and apply acceleration to each other’s movement. Therefore I intended to simulate this process. I watched the videos for forces from the Coding Train, and learned how to generate a N-body system. However, I wasn’t able to simulate the solar system in the end. It’s because the real parameters are extremely large, and the gravitational interaction is actually far more complicated than I expected. It is impossible to simulate it using only Newton’s gravitational law. Therefore although I was not satisfied with the final product, I had no better solutions and had to turn it in. But I will definitely try it in the next weeks!

Part 2: Coding

The basis of my coding gained lots of help from the Coding Train. I defined one class called “Mover”, which is basically every planet in the system. I set the position, initial velocity, mass, and acceleration for every object of the class. And then I defined an attract() function that calculates the distance between two planets to get the mutual force using Newton’s gravitational law. I’ve got an array for storing all the Mover objects, and calculate the force between every single pair of movers.

The fun part was to design the user interface that enables the players of the system to generate their new planets in whatever mass and initial velocity they want. The user simply has to press the up or down arrow key to adjust the mass of the planet and drag and drop the mouse to release a new planet in any direction.

The larger the circle, the larger the mass. The longer the arrow, the higher the initial speed.

However, if I draw the circle and arrow in the mousePressed and mouseDragged functions, there will be a problem. The mousePressed will only be called once at the exact moment the mouse is being pressed, and the mouseDragged will also stop looping when the mouse position doesn’t move, even if the mouse is still triggered. This will cause the circle and arrow to be covered by the background of the next draw loop.

To solve this, I store every parameter of the detail of the circle and arrow in some variable, and draw them in the draw loop under certain conditions.

  // in draw:
  if (mouseIsPressed) {
    stroke(255);
    strokeWeight(1);
    noFill();
    ellipse(mouseXStore, mouseYStore, newSize, newSize);
    arrow(mouseXStore, mouseYStore,mouseX, mouseY);
  } else {
    ellipse(mouseX, mouseY, newSize, newSize);
  }
  
  if (keyIsPressed) {
    if (keyCode === UP_ARROW ) {
      newSize += 0.5;
    } else if (keyCode === DOWN_ARROW) {
      newSize -= 0.5;
    } else if (key == "c" || key == "C") {
      for (let i = movers.length - 1; i >= 0; i --) {
        movers.splice(i,1);
      }
    }
  }
  noStroke();
  fill(255);
  text("Drag and release to create a new planet", 10,15);
  text("Press up and down arrow to change planet mass", 10, 25);
}


function mousePressed() {
  mouseXStore = mouseX;
  mouseYStore = mouseY;
}


function mouseReleased() {
  movers.push(new Mover(mouseXStore, mouseYStore, newDir.x, newDir.y, newInitSpd, newSize**2)); 
}


function arrow(x1,y1,x2,y2) {
  let vec = createVector(x2-x1,y2-y1);
  let dist = vec.mag();
  newInitSpd = dist/30;
  stroke(255);
  strokeWeight(1);
  fill(255);
  line(x1,y1,x2,y2);
  push();
  translate(mouseX, mouseY);
  let dir = atan2(vec.y, vec.x);
  rotate(dir);
  triangle(0,0,-3,-2,-3,2);
  pop();
  newDir = vec.normalize();
}

Part 3: Reflection

I don’t think I did well on this assignment. I failed to learn more about the physics principles of gravity interaction and didn’t achieve my initial goal of simulating the solar system. Instead, I only did a customizable n-body system. Given that I had two semesters’ experience in p5js coding, I should try to create more original and math/physics-based projects next time!!!

Coding Assignment – Week #2

This week’s project was inspired by ducks and their swimming movement. Here is a short calming 5 hour video of the phenomenon in question:


Here is the sketch:

As I was scrolling through my camera roll, I noticed that I had quite a few videos of ducks swimming by the shore of a pond. I remembered the mouse tracking example task that we did last class, and it occurred to me that the walker was moving in a similar fashion like the ducks following a human on the shore who is holding a piece of bread. I thus wanted to alter the code of the task to simulate a group of swimming ducks.

To translate this idea into code, I decided to create a scenario where the ducks were drawn towards a fish instead of a human with bread, adding a more natural and engaging touch. Additionally, I aimed to introduce a bit of unpredictability to mimic real-life scenarios by randomizing the number of ducks with each sketch as they swim in both smaller and larger groups. Since they often come together in one spot, I wanted them to form circular patterns while changing positions.

In order to achieve this, I used object-oriented programming to create the duck objects, and vectors to simulate their movement. For instance, I employed vectors to determine the distance between each duck and the fish cursor. This enabled me to simulate the ducks’ natural tendency to swim toward a target, just like real ducks follow food. By calculating these distances and adjusting the ducks’ directions accordingly, this behavior was replicated in code.

The part of the code for which I was proud of was the snipet where I tried to make the ducks avoid collisions. To achieve that I needed to calculate a ‘pushForce’ vector that points away from the current duck, which was then assigned as a new acceleration vector. Here is the snipet:

avoidCollisions(ducks) {
    let avoidance = createVector(0, 0);
    
    //Looping through each of the ducks
    for (let i = 0; i < ducks.length; i++) {
      // Checking if the current duck being checked is not the same as this duck
      if (ducks[i] !== this) {
        // Calculating the distance between this duck and the current duck in the loop
        let distance = p5.Vector.dist(this.position, ducks[i].position);
        // Checking if the distance is less than the desired distance
        if (distance < minDistance ) {
          // // Calculating a 'pushForce' vector that points away from the current duck
          let pushForce = p5.Vector.sub(this.position, ducks[i].position);
          // Setting the magnitute
          pushForce.setMag(0.1); 
          // Adding the 'pushForce' vector to the 'avoidance' vector
          avoidance.add(pushForce);
        }
      }
    }
    // Changing the acceleration to the 'avoidance' vector
    this.acceleration = avoidance;
  }

Although the movement of the fish was not my main concern, I was very satisfied with how it turned out. The little glitches that occur during the cursor movement actually appear similar to how smaller fish actually tend to have uneven swimming patterns and often do sudden turns and unexpected movements.

For further improvements, I would love to make the ducks also swim in a V like shape, where one of them would take the lead and others would stay a little behind forming the V. Another idea could be to simulate the ducks going underwater and disappearing for a while why they attempt to catch the fish. Of course, it would also be a big plus to improve the visual appearance of the ducks, and perhaps simulate some water movement as well.

Coding assignment – week 2

FireFlies

For this assignment I wanted to mimic the movements of organisms that live in groups. My first idea was to center it around a school or fish or a flock of birds. But after some experimentation I realized coding a swarm of fireflies would work well with the simplistic design I was going for, since we normally see them as bright points anyway in real life. The video below is what I based my movement code on.

Fireflies are known for their enchanting flashing behavior, and in this project, I tried to mimic their signature glow and also added an interactive element by controlling their movement using the mouse pointer. This combination results in a visually engaging and interactive experience.

How It Works:
  • Flashing Behavior: I use trigonometric functions to generate the rhythmic flashing of fireflies. The phase, frequency, and amplitude of the flash are randomized to add variety.
  • Movement Control: Fireflies’ movement is controlled by acceleration vectors. We apply forces to simulate attraction or repulsion from the mouse pointer and Perlin noise for random motion.
  • Interactive Mouse Control: When the mouse is nearby, fireflies either move away from it (repulsion), creating dynamic patterns.
  • Canvas Wrapping: To prevent fireflies from leaving the canvas, we use conditional statements to wrap them around when they reach the canvas boundaries.
What I like about it:
    • Realistic Behavior: The combination of flashing patterns, dynamic movement, and interactive control creates a realistic and captivating simulation of firefly behavior.
    • Interactivity: The ability to influence the fireflies’ behavior with the mouse adds an element of interactivity, making it both visually appealing and engaging for users.
    • Exploration: Users can experiment with different mouse movements and observe how the fireflies respond, making each interaction a unique experience.
Difficult code:

The most challenging part was trying to make the mouse pointer repel the fireflies within a specific range, but I managed to do it below by reversing the unit vector of the fireflies pointing towards the mouse pointer.

let desired = p5.Vector.sub(target, this.position);
    let d = desired.mag();
    if (d < 50) {
      desired.setMag(this.maxSpeed);
      desired.mult(-1);
      let steer = p5.Vector.sub(desired, this.velocity);
      steer.limit(this.maxForce);
      this.applyForce(steer);
    }

 

Coding Assignment – Week 2

For this assignment I was inspired by a video I took during the summer break of a group of ducks that left the lake in search for food. Every time people tossed seeds they ran as group towards them.

duckVideo

I attempted to mimic their movement in my code assigning each duck different acceleration while still having them all move in the same direction. I decided to attach to the mouse’s movement seeds to indicate what it is that the ducks are following.

The code was relatively simple however there was one section that was somewhat challenging for me to explore, that is, regarding the bounce back of the ducks. Initially before measuring the distance between the ducks and limiting their movement to avoid their overlap, the ducks lied on top of each other making their movement unrealistic.

Below is a snippet of the part of the code I found challenging:

for (let singleDuck of newDuck) {
      if (singleDuck !== this) 
      {
        //measures distance between ducks
        let distance = p5.Vector.dist(singleDuck.position, this.position);

        if (distance < (this.radius *2)) {
          // Calculate the overlap amount
          let overlap = (this.radius *2) - distance;
          // Calculate the vector from this duck to the new duck
          let direction = p5.Vector.sub(this.position, singleDuck.position);
          direction.normalize();
          // Calculate the bounce back force
          let collide = p5.Vector.mult(direction, overlap * 0.1);
          // Apply bounce back to the duck by adding value to acceleration
          this.acceleration.add(collide);
        }
      }
    }

First I made the move method of the Duck class specific to the argument newDuck, that is, it runs in relation to the newDuck variable. I did that because I need it to check for the collisions while handling the movement of the ducks.

Then in this method I created a for loop that runs through all the variables ‘singleDuck’ of the collection ‘newDuck’. In this for loop there is an if statement that runs as long as ‘newDuck’ is not being compared by itself ‘this’. This if statement checks for the distance between the ducks and ensures they do not overlap but rather collide and bounce. It does so by detecting their direction, and scaling the magnitude of it then adding to the value of acceleration.  This leads to a more realistic and natural movement for the ducks.

 

Reflection and Ideas:

I am quite proud of how this code turned out. I think in the future I could elements that show more interactivity between the ducks and the seeds. This could be done through the seeds disappearing gradually as the ducks come across them. This at the moment is not something I know how to accomplish but I look forward to learning it.

 

Below is the code for reference: 

https://editor.p5js.org/dhabialhosani/sketches/iLiewRjl7

 

Assignment 2 – The Heliocentric Model

I sometimes find it crazy that we live on a planet. Out of billions of celestial objects in the universe, we exist on this beautiful sphere (not technically) – Earth.

This is the moving object I decided to use, because everything that exists in our reality belongs to this planet. The motion on this project involves a depiction of the Heliocentric modal of the universe, proposed by Nicolaus Copernicus in the 16th century, that asserts that the Sun is at the center of our solar system, with the planets, including Earth, orbiting around it.

However, the earth doesn’t just orbit the Sun. It also rotates on its own axis, which happens to be tilted ~23 degrees. This truly extraordinary fact of the universe, which took humans thousands of years to realize, is what is depicted in the sketch.

An interesting part of the sketch is the fabric of cosmos. It is a metaphorical concept often used in cosmology and physics to describe the underlying structure of the universe. It basically means that space itself is not empty but is woven with the fabric of spacetime, a four-dimensional framework where all matter and energy exist and interact. I wish I could show all four dimensions in this project, but this is what I could build in a short span of time. Oh wait, that could be a future improvement for the project!

Here’s the sketch. You can interact with it as well – try to hold-click and drag using your mouse.

The tiny green sphere is for a point of reference. It shows that the earth is tilted and is rotating around an axis.

As mentioned before a cool part of this project is the Fabric. Here’s how I was able to implement it.

class Fabric {
  constructor(rows, cols, spacing) {
    this.rows = rows;
    this.cols = cols;
    this.spacing = spacing;
    this.points = [];

    // create an array of PVectors to represent points in the fabric
    for (let y = 0; y < this.rows; y++) {
      for (let x = 0; x < this.cols; x++) {
        this.points.push(createVector(x * this.spacing - this.cols * this.spacing / 2, y * this.spacing - this.rows * this.spacing / 2, 0));
      }
    }
  }

  display() {
    push();
    stroke(255);
    strokeWeight(0.5);
    noFill();
    for (let i = 0; i < this.points.length; i++) {
      vertex(this.points[i].x, this.points[i].y, this.points[i].z);
    }
    pop();
  }
}

Week 2 Assignment: Documentation (Zulfkhar Maukey)

Raindrop Simulation Documentation

Introduction

The Raindrop Simulation is a p5.js project that simulates the behavior of raindrops falling from the sky. This project is an example of using rules and physics to replicate a real-world natural phenomenon. In this documentation, we will provide a detailed description of what the simulation does, how it works, and how users can interact with it.

Project Description

What It Does

The Raindrop Simulation replicates the following characteristics of raindrops:

  1. Gravity: Raindrops are affected by gravity, causing them to accelerate as they fall.
  2. Wind: A simulated wind force pushes raindrops horizontally, creating a drifting effect.
  3. Variable Gravity: Users can interact with the simulation by temporarily increasing the gravity force when the “Up Arrow” key is pressed. This causes raindrops to fall faster and create a denser rainfall.
  4. Splash Effect: When a raindrop hits the ground (the bottom of the canvas), it creates a splash effect.
  5. Raindrop Removal: Users can decrease the gravity force by pressing the “Down Arrow” key, making raindrops fall more slowly. This allows for the removal of raindrops from the simulation.
User Interaction

The user can interact with the Raindrop Simulation using keyboard inputs:

  • Up Arrow Key: When pressed, it increases the gravity temporarily, causing raindrops to fall faster and more intensely.
  • Down Arrow Key: When pressed, it decreases the gravity, making raindrops fall more slowly. This also allows for the removal of raindrops from the simulation.

Implementation

Setup and Draw Functions

In the p5.js setup function:

  • The canvas is created with a size of 400×400 pixels.
  • A predefined number of raindrops (100 in this case) are created and stored in an array.
  • The initial gravity value is set to 0.2.

In the p5.js draw function:

  • The canvas is cleared with a light gray background (RGB 220, 220, 220).
  • Wind force is applied to each raindrop, creating a horizontal drifting effect.
  • Gravity is applied to each raindrop, causing them to accelerate vertically.
  • The position and appearance of each raindrop are updated and displayed on the canvas.
Raindrop Class

The Raindrop class represents individual raindrops in the simulation. Each raindrop has the following properties and methods:

  • constructor: Initializes the position, velocity, length, and splash state of each raindrop.
  • applyForce(force): Applies a force vector to the raindrop, affecting its velocity.
  • update(): Updates the raindrop’s position based on its velocity and applies constraints to keep it within the canvas.
  • splash(): Checks if a raindrop has hit the ground and creates a splash effect if it has.
  • display(): Renders the raindrop as a blue line and calls the splash() method to display the splash effect.

Demo

Full-source code

Conclusion

The Raindrop Simulation project successfully replicates the behavior of falling raindrops and provides an interactive experience for users. It showcases how computational rules and physics can be used to simulate natural phenomena. Here are some key reflections on the project:

  • Realism: The simulation captures the basic behavior of raindrops, including gravity, wind, and the splash effect, providing a visually convincing representation.
  • Interactivity: User interaction via the keyboard adds an engaging element, allowing users to control the intensity of the rainfall and observe the immediate impact on the simulation.
  • Educational Value: This project serves as an educational tool, demonstrating principles of physics and programming in an accessible and fun manner.

While the Raindrop Simulation is functional and engaging, there is room for improvement and expansion. Here are some ideas for future work:

  1. Particle Interaction: Add more complex interactions between raindrops, such as collisions or cohesion, to enhance realism.
  2. Dynamic Wind: Implement a more dynamic wind pattern, including changes in wind direction and intensity over time.
  3. Realistic Splash: Enhance the splash effect by considering the angle and speed of impact to create more realistic splashes.