/* float swt = 0.001; //separation float awt = 1.0; //Alignment float cwt = .05; //Cohesian float maxspeed = .3; //max speed float maxforce = 0.001; //max force */ float swt = 0.03; //separation float awt = 1.0; //Alignment float cwt = .05; //Cohesian float maxspeed = .3; //max speed float maxforce = 0.001; //max force class Boid { PVector loc; PVector vel; PVector acc; float r; color c; float neighbordist = 400.0f; boolean xIsOut; boolean yIsOut; //fish items float recentx, recenty, currentx, currenty, start; float [] xTop, yTop, xBottom, yBottom; PImage bill; color fishColor; int arrayCounter; int fishSize = 66; //this must be divisible by 6 //end fish items Boid() { acc = new PVector(0,0); vel = new PVector(random(-1,1),random(-1,1)); loc = new PVector(width/2,height/2); r = 90; c = color(255,255,255,100); xIsOut = false; //check to see if anything is out of bounds yIsOut = false; //fish items start = random(0,5); bill = loadImage("USD.jpg"); fishColor = bill.get(50, 25); fill(fishColor); //stroke (0); xTop = new float[7]; yTop = new float[7]; xBottom = new float[6]; yBottom = new float[6]; //end fish items } void run(ArrayList boids) { flock(boids); //calculate forces on the flock as a whole update(); //apply forces on each indivisual fish //borders(); render(); } // We accumulate a new acceleration each time based on three rules void flock(ArrayList boids) { PVector sep = separate(boids); // Separation PVector ali = align(boids); // Alignment PVector coh = cohesion(boids); // Cohesion // Arbitrarily weight these forces sep.mult(swt); ali.mult(awt); coh.mult(cwt); // Add the force vectors to acceleration acc.add(sep); acc.add(ali); acc.add(coh); } // Method to update location void update() { //check borders only if we aren't already recovering from out of bounds //if (xIsOut == false) {xBorders();} //if (yIsOut == false) {yBorders();} borders(); //if we've hit a border, set the item to steer towards the center vel.add(acc); // Update velocity // Limit speed vel.limit(maxspeed); loc.add(vel); // Reset accelertion to 0 each cycle acc.mult(0); } void seek(PVector target) { acc.add(steer(target,false)); } void arrive(PVector target) { acc.add(steer(target,true)); } // A method that calculates a steering vector towards a target // Takes a second argument, if true, it slows down as it approaches the target PVector steer(PVector target, boolean slowdown) { // HACK TO STOP ARRIVING //slowdown = false; PVector steer; // The steering vector PVector desired = PVector.sub(target,loc); // A vector pointing from the location to the target float d = desired.mag(); // Distance from the target is the magnitude of the vector // If the distance is greater than 0, calc steering (otherwise return zero vector) if (d > 0) { // Normalize desired desired.normalize(); // Two options for desired vector magnitude (1 -- based on distance, 2 -- maxspeed) if ((slowdown) && (d < 100.0f)) desired.mult(maxspeed*(d/100.0f)); // This damping is somewhat arbitrary else desired.mult(maxspeed); // Steering = Desired minus Velocity steer = PVector.sub(desired,vel); steer.limit(maxforce); // Limit to maximum steering force } else { steer = new PVector(0,0); } return steer; } void render() { float theta = vel.heading2D() + radians(180); fill(fishColor); pushMatrix(); translate(loc.x,loc.y); rotate(theta); //start fish float wiggle = start; arrayCounter = 0; // This keeps track of what point we're at as we add info to the top and bottom arrays recentx = 0; //set everything to 0 each time through. This is where recenty = 0; currentx = 0; currenty = 0; //Lets get the x and y coordinates for our fish for (int x = 0; x < fishSize; x+= fishSize/6) { //this would be 150 for a big one or anything divisable by 6), and 25 currentx = x; currenty = sin(wiggle)*5; //the *# controls how much of a wiggle occurs float xpoint = currentx-recentx; float ypoint = currenty-recenty; //find the points for the top of the fish shape if (x == 0) { //the nose should not move around //vertex (currentx,currenty); xTop[arrayCounter] = currentx; //store the info in the array yTop[arrayCounter] = currenty; xBottom[arrayCounter] = currentx; yBottom[arrayCounter] = currenty; }//end if else{ xTop[arrayCounter] = currentx+ypoint; //store the info in the array yTop[arrayCounter] = currenty-xpoint; xBottom[arrayCounter] = currentx-ypoint; //store the info in the array yBottom[arrayCounter] = currenty+xpoint; if (arrayCounter==4){ //a special situatio for the pinch of the tail xTop[arrayCounter] = currentx+ypoint/4; //store the info in the array yTop[arrayCounter] = currenty-xpoint/4; xBottom[arrayCounter] = currentx-ypoint/4; //store the info in the array yBottom[arrayCounter] = currenty+xpoint/4; }//end if }//end else if (x == (fishSize-(fishSize/6))) { //an extra, unmoving point for the end of the tail xTop[arrayCounter+1] = currentx; yTop[arrayCounter+1] = currenty; //ellipse(currentx,currenty, 2, 2); }//end if tail point recentx = currentx; //cleanup for the next time recenty = currenty; wiggle += 0.8; arrayCounter++; }//end for loop to load data //now draw the fish, background first! //stroke (0); noStroke(); beginShape(); //first draw the top half for (int i = 0; i < xTop.length; i++) { vertex(xTop[i],yTop[i]); }//end for //now draw the bottom half for (int i = xBottom.length-1; i >= 0; i--) { vertex(xBottom[i],yBottom[i]);} endShape(); //Now draw the bill on top!: beginShape(); texture(bill); //first draw the top half for (int i = 1; i < 4; i++) { vertex(xTop[i],yTop[i], map(i, 1, 3, 1, 100), 0); } //now draw the bottom half for (int i = xBottom.length-3; i >= 0; i--) { if (i==0) { } else if (i==1) { {vertex(xBottom[i],yBottom[i], 0, 50);} } else{vertex(xBottom[i],yBottom[i], map(i, xBottom.length-3, 0, 100, 0), 50);} } endShape(); start += 0.05; //move where the sin wave starts from so it moves //end fish popMatrix(); }//end display // Separation // Method checks for nearby boids and steers away PVector separate (ArrayList boids) { float desiredseparation = 25.0f; PVector sum = new PVector(0,0,0); int count = 0; // For every boid in the system, check if it's too close for (int i = 0 ; i < boids.size(); i++) { Boid other = (Boid) boids.get(i); float d = PVector.dist(loc,other.loc); // 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(loc,other.loc); diff.normalize(); diff.div(d); // Weight by distance sum.add(diff); count++; // Keep track of how many } } // Average -- divide by how many if (count > 0) { sum.div((float)count); } return sum; } // Alignment // For every nearby boid in the system, calculate the average velocity PVector align (ArrayList boids) { PVector sum = new PVector(0,0,0); int count = 0; for (int i = 0 ; i < boids.size(); i++) { Boid other = (Boid) boids.get(i); float d = PVector.dist(loc,other.loc); if ((d > 0) && (d < neighbordist)) { sum.add(other.vel); count++; } } if (count > 0) { sum.div((float)count); sum.limit(maxforce); } return sum; } // Cohesion // For the average location (i.e. center) of all nearby boids, calculate steering vector towards that location PVector cohesion (ArrayList boids) { PVector sum = new PVector(0,0,0); // Start with empty vector to accumulate all locations int count = 0; for (int i = 0 ; i < boids.size(); i++) { Boid other = (Boid) boids.get(i); float d = PVector.dist(loc,other.loc); if ((d > 0) && (d < neighbordist)) { sum.add(other.loc); // Add location count++; } } if (count > 0) { sum.div((float)count); return steer(sum,false); // Steer towards the location } return sum; } // Wraparound /*void borders() { if (loc.x < r) vel.x = -vel.x; //ri is an arbitrary number to let the fish look like they're swimming off screen if (loc.y < r) vel.y = -vel.y; if (loc.x > width-r) vel.x = -vel.x; if (loc.y > height-r) vel.y = -vel.y; } */ void borders() { PVector target = new PVector(width/2, height/2); PVector temp = steer(target,false); if (loc.x < r) acc.x = temp.x; //ri is an arbitrary number to let the fish look like they're swimming off screen if (loc.y < r) acc.y = temp.y; if (loc.x > width-r) acc.x = temp.x; if (loc.y > height-r) acc.y = temp.y; } /* void borders() { if (loc.x < -r) loc.x = width+r; //ri is an arbitrary number to let the fish look like they're swimming off screen if (loc.y < -r) loc.y = height+r; if (loc.x > width+r) loc.x = -r; if (loc.y > height+r) loc.y = -r; }*/ }