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