Predator-Prey simulation
For this assignment, I wanted to recreate an underwater chase scene. My goal was to show simulation through autonomous agents, like a single predatory shark chasing a school of fish. The fish reacts to the shark’s actions by fleeing. Each agent has its own set of rules and behaviors that it follows in their 2D ocean.
Implementation:
- The Shark’s Path: To control the shark’s movement, I used a Perlin noise algorithm. This created a smooth, random path that mimics how unpredictable a real shark’s patrol through the water is.
- Fish Fleeing: In this state, their behavior changes dramatically. They prioritize moving away from the shark over any other actions they might be taking, such as wandering
- Boundary Constraints: I coded the fish to wrap around the edges of the canvas so they stay in the canvas
- Shark Movement: Instead of being directly controlled, the shark follows a path made by perlin noise. I’ve tuned this function to keep the shark from moving randomly and give its hunt a bit of randomness. Also, the shark slows down when it gets closer to its target.
Sketch:
Code:
The following is the function for sharks seeking their target which is calculated by Perlin noise.
class Shark { seek(target) { let desired = p5.Vector.sub(target, this.position); let distance = desired.mag(); desired.normalize(); if (distance < 100) { let m = map(distance, 0, 100, 0, this.maxSpeed); desired.mult(m); // Slow down as it gets closer to the target } else { desired.mult(this.maxSpeed); } let steer = p5.Vector.sub(desired, this.velocity); steer.limit(this.maxForce); this.applyForce(steer); } }
- The
seek
method in theShark
class steers the shark towards a target. - It calculates the direction to the target and if the shark is within 100 pixels, it slows down proportionally to the distance to avoid overshooting.
- The
map
function adjusts the shark’s speed dynamically, allowing for a gradual stop as it reaches the target. - This prevents the shark from ‘spazzing’ or jittering when it gets close to where it wants to go.
The following is the function for fish fleeing the shark
class Fish { flee(predator) { let desired = p5.Vector.sub(this.position, predator.position); let d = desired.mag(); if (d < 100) { // If the shark is within 100 pixels desired.setMag(this.maxSpeed); // Set maximum speed let steer = p5.Vector.sub(desired, this.velocity); steer.limit(this.maxForce); // Limit the force to be applied this.applyForce(steer); } } }
- The
flee
function in theFish
class calculates the escape direction from the shark. - If the shark is within a certain range, the fish accelerates to its top speed away from the shark.
- This quick response mimics a fish’s instinct to escape predators.
Challenges:
- Precision in Shark Movement: Improving the shark’s movement to stop it from “spazzing” as it gets to its target was a difficult job that required slowing the velocity as it got closer to the target.
- Fish Behavior Realism: Making flocking behavior was hard to implement because you had to find a fine balance between random movement and organized group dynamics. After a shark chase, there were difficulties getting the fish to gather back into a proper formation. I think this aspect still needs some work to make it more realistic.
Future Improvements:
- User Interaction Features: I want to look into ways for users to connect more directly with the simulation, such as using different inputs to change the path of the shark or the fish.
- Ecosystem Development: I like the idea of adding more species and environmental features, like currents or obstacles, to make the experience more interesting.
- Develop Flocking Behavior: To make the fish’s reaction seem real, the flocking and evasion algorithms have to be tweaked to match how fish move naturally.