For this assignment I took inspiration from the Jaws poster. I created the shark using primitive shapes and followed that theme for the fish and and the coral in the background. The shark pops up when the mouse is clicked. The fish move around the screen continuously using a flock and boid class to change the position and create the fish.
-Tiffany Marin
Code
Shark shark;
Flock flock;
int bubbleY = 490;
int bubbleX = 250;
void setup() {
size(500, 500, P2D);
background(#3296C6);
shark = new Shark();
flock = new Flock();
for(int i = 0; i < 100; i++){
flock.addBoid(new Boid(width/2,height/2));
}
}
void draw() {
background(#3296C6);
for(int i = 0; i < 50; i++){
fill(#79C5EA,63);
triangle(95, 0, 40,250,110,0);
triangle(220,0,230,260,235,0);
triangle(350,0,410,250,365,0);
}
drawBackground();
flock.run();
if(mousePressed){
shark.drawShark();
}
}
void moveBubble(){
bubbleX = bubbleX – 5;
bubbleY = bubbleY – 10;
}
void drawBackground(){
//big coral
noStroke();
fill(#984733);
ellipse(50,500,150,60);
ellipse(350,490,150,60);
ellipse(400,460,120,40);
ellipse(480,430,100,60);
//medium coral
fill(#FC5B42);
strokeWeight(2);
stroke (#F08049);
ellipse(50,500,125,40);
ellipse(40,480,125,20);
ellipse(70,470,125,35);
ellipse(50,450,125,30);
ellipse(340,485,125,50);
ellipse(360,460,125,40);
ellipse(480,420,115,30);
ellipse(430,440,115,30);
ellipse(380,440,125,20);
ellipse(400,420,123,35);
//Small coral
fill(#FC8E66);
ellipse(340,435,60,20);
ellipse(40,470,105,20);
ellipse(70,435,90,15);
ellipse(460,405,80,25);
}
void keyPressed() {
if (key == ‘s’) {
saveFrame(“drawing-####.png”);
}
}
class Shark{
PShape mini;
Shark(){
stroke(#9EA7AA);
fill(#9EAEB4);
}
//Function to create the shark
void drawShark(){
//Back of shark
noStroke();
fill(#9EAEB4);
beginShape();
vertex(150, 500);
vertex(350, 500);
vertex(350, 300);
curveVertex(350,300);
curveVertex(260,200);
curveVertex(240,200);
curveVertex(150,300);
vertex(150, 300);
endShape();
//Middle of shark
noStroke();
fill(#D7DEE0);
beginShape();
vertex(150, 500);
vertex(350, 500);
vertex(330, 300);
curveVertex(320,300);
//curveVertex(260,180);
curveVertex(260,220);
curveVertex(240,220);
//curveVertex(150,)
curveVertex(170,300);
vertex(170, 300);
endShape();
//Middle shark layer
beginShape();
//quad();
endShape();
//black eye
fill(#080808);
ellipse(160,300,25,40);
ellipse(340,300,25,40);
//pupil
fill(#FFFFFF);
ellipse(155,295,10,10);
ellipse(336,295,10,10);
//mouth
beginShape();
//Lips of mouth
fill(#AF1919);
rect(185,345,130,70);
arc(250,345,130,55,PI,TWO_PI);
arc(250,415,130,55,0,PI);
//Inside of mouth
fill(#FFFFFF);
rect(190,350,120,60);
arc(250,350,120,50,PI,TWO_PI);
arc(250,410,120,50,0,PI);
//teeth of the shark
fill(#080808);
rect(190,350,120,60);
//Top teeth
triangle(200,350,210,332,220,350);
triangle(220,350,230,326,240,350);
triangle(240,350,250,325,260,350);
triangle(260,350,270,326,280,350);
triangle(280,350,290,332,300,350);
//Bottom teeth
triangle(200,400,210,430,220,400);
triangle(220,400,230,435,240,400);
triangle(240,400,250,436,260,400);
triangle(260,400,270,435,280,400);
triangle(280,400,290,430,300,400);
endShape();
}
}
// The Flock (a list of Boid objects)
// Code from Daniel Shiffman
// Url: https://www.processing.org/examples/flocking.html
class Flock {
ArrayList<Boid> boids; // An ArrayList for all the boids
Flock() {
boids = new ArrayList<Boid>(); // Initialize the ArrayList
}
void run() {
for (Boid b : boids) {
b.run(boids); // Passing the entire list of boids to each boid individually
}
}
void addBoid(Boid b) {
boids.add(b);
}
void changeColor(){
//float g
}}
// Code from Daniel Shiffman
// Url: https://www.processing.org/examples/flocking.html
class Boid {
PVector position;
PVector velocity;
PVector acceleration;
float r;
float maxforce; // Maximum steering force
float maxspeed; // Maximum speed
Boid(float x, float y) {
acceleration = new PVector(0, 0);
// This is a new PVector method not yet implemented in JS
// velocity = PVector.random2D();
// Leaving the code temporarily this way so that this example runs in JS
float angle = random(TWO_PI);
velocity = new PVector(cos(angle), sin(angle));
position = new PVector(x, y);
r = 2.0;
maxspeed = 2;
maxforce = 0.03;
}
void run(ArrayList<Boid> boids) {
flock(boids);
update();
borders();
render();
}
void applyForce(PVector force) {
// We could add mass here if we want A = F / M
acceleration.add(force);
}
// We accumulate a new acceleration each time based on three rules
void flock(ArrayList<Boid> boids) {
PVector sep = separate(boids); // Separation
PVector ali = align(boids); // Alignment
PVector coh = cohesion(boids); // Cohesion
// Arbitrarily weight these forces
sep.mult(1.5);
ali.mult(1.0);
coh.mult(1.0);
// Add the force vectors to acceleration
applyForce(sep);
applyForce(ali);
applyForce(coh);
}
// Method to update position
void update() {
// Update velocity
velocity.add(acceleration);
// Limit speed
velocity.limit(maxspeed);
position.add(velocity);
// Reset accelertion to 0 each cycle
acceleration.mult(0);
}
// A method that calculates and applies a steering force towards a target
// STEER = DESIRED MINUS VELOCITY
PVector seek(PVector target) {
PVector desired = PVector.sub(target, position); // A vector pointing from the position to the target
// Scale to maximum speed
desired.normalize();
desired.mult(maxspeed);
// Above two lines of code below could be condensed with new PVector setMag() method
// Not using this method until Processing.js catches up
// desired.setMag(maxspeed);
// Steering = Desired minus Velocity
PVector steer = PVector.sub(desired, velocity);
steer.limit(maxforce); // Limit to maximum steering force
return steer;
}
void render() {
// Draw a triangle rotated in the direction of velocity
float theta = velocity.heading2D() + radians(90);
// heading2D() above is now heading() but leaving old syntax until Processing.js catches up
float g = random(100,300);
float b = random(100,300);
fill(94, g, b);
stroke(94,g,b);
pushMatrix();
translate(position.x, position.y);
rotate(theta);
beginShape(TRIANGLES);
vertex(0, -r*2);
vertex(-r, r*2);
vertex(r, r*2);
endShape();
popMatrix();
}
// Wraparound
void borders() {
if (position.x < -r) position.x = width+r;
if (position.y < -r) position.y = height+r;
if (position.x > width+r) position.x = -r;
if (position.y > height+r) position.y = -r;
}
// Separation
// Method checks for nearby boids and steers away
PVector separate (ArrayList<Boid> boids) {
float desiredseparation = 25.0f;
PVector steer = new PVector(0, 0, 0);
int count = 0;
// For every boid in the system, check if it’s too close
for (Boid other : boids) {
float d = PVector.dist(position, other.position);
// If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself)
if ((d > 0) && (d < desiredseparation)) {
// Calculate vector pointing away from neighbor
PVector diff = PVector.sub(position, other.position);
diff.normalize();
diff.div(d); // Weight by distance
steer.add(diff);
count++; // Keep track of how many
}
}
// Average — divide by how many
if (count > 0) {
steer.div((float)count);
}
// As long as the vector is greater than 0
if (steer.mag() > 0) {
// First two lines of code below could be condensed with new PVector setMag() method
// Not using this method until Processing.js catches up
// steer.setMag(maxspeed);
// Implement Reynolds: Steering = Desired – Velocity
steer.normalize();
steer.mult(maxspeed);
steer.sub(velocity);
steer.limit(maxforce);
}
return steer;
}
// Alignment
// For every nearby boid in the system, calculate the average velocity
PVector align (ArrayList<Boid> boids) {
float neighbordist = 50;
PVector sum = new PVector(0, 0);
int count = 0;
for (Boid other : boids) {
float d = PVector.dist(position, other.position);
if ((d > 0) && (d < neighbordist)) {
sum.add(other.velocity);
count++;
}
}
if (count > 0) {
sum.div((float)count);
// First two lines of code below could be condensed with new PVector setMag() method
// Not using this method until Processing.js catches up
// sum.setMag(maxspeed);
// Implement Reynolds: Steering = Desired – Velocity
sum.normalize();
sum.mult(maxspeed);
PVector steer = PVector.sub(sum, velocity);
steer.limit(maxforce);
return steer;
}
else {
return new PVector(0, 0);
}
}
// Cohesion
// For the average position (i.e. center) of all nearby boids, calculate steering vector towards that position
PVector cohesion (ArrayList<Boid> boids) {
float neighbordist = 50;
PVector sum = new PVector(0, 0); // Start with empty vector to accumulate all positions
int count = 0;
for (Boid other : boids) {
float d = PVector.dist(position, other.position);
if ((d > 0) && (d < neighbordist)) {
sum.add(other.position); // Add position
count++;
}
}
if (count > 0) {
sum.div(count);
return seek(sum); // Steer towards the position
}
else {
return new PVector(0, 0);
}
}
}