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

Leave a Reply

Your email address will not be published. Required fields are marked *