Created
February 6, 2015 23:52
-
-
Save Craigson/ba9acf4f2431b6902fa3 to your computer and use it in GitHub Desktop.
Movers with the ability to steer and a mutual repulsion force, traveling through regions in which a drag force is applied
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Mover [] movers; | |
| Patch [] patches; | |
| float count = 0; | |
| void setup() { | |
| size(1200, 675); | |
| movers = new Mover[150]; //create an array of movers | |
| patches = new Patch[10]; //create an array of friction patches | |
| for (int i = 0; i < movers.length; i++) { | |
| movers[i] = new Mover(); | |
| } | |
| for (int j = 0; j < patches.length; j++) { | |
| patches[j] = new Patch(); | |
| } | |
| } | |
| void draw() { | |
| background(255); | |
| PVector mouse = new PVector(mouseX, mouseY); //create a vector that stores the mouse location | |
| for (int i = 0; i < patches.length; i++) { | |
| patches[i].display(); | |
| } | |
| //check every mover against every other mover. Apply the force that's determined | |
| //by the repel() method for every mover so that the movers repel one another | |
| //and don't bunch together as they follow the mouse | |
| for (int j = 0; j < movers.length; j++) { | |
| for (int l = 0; l < movers.length; l++) { | |
| if (j!=l) { //mover musn't check against itself | |
| PVector force = movers[l].repel(movers[j]); | |
| movers[j].applyForce(force); | |
| //println(force); | |
| } | |
| } | |
| //loop through both each patch to check if the mover is over the patch, | |
| //if it is, execute the calcDrag method and apply the drag force | |
| for (int k = 0; k < patches.length; k++) { | |
| if (patches[k].isInside(movers[j]) == true) { | |
| movers[j].applyForce(patches[k].calcDrag(movers[j])); | |
| movers[j].k = color(100, 200, 100); //change the colour if the mover is over the patch | |
| } else { | |
| movers[j].applyForce(movers[j].initForce); //if the mover is not within | |
| //the drag zone, apply the initial force assigned in the constructor | |
| } | |
| } | |
| movers[j].seek(mouse); //the seek() method takes the mouse position as a paramet and | |
| //ensures that the movers steer towards the mouse | |
| movers[j].update(); | |
| movers[j].checkEdges(); | |
| movers[j].display(); | |
| } | |
| println(frameRate); | |
| } | |
| class Mover { | |
| PVector loc, vel, acc, initForce; | |
| float mass; | |
| float rad; | |
| float maxSpeed, maxForce; | |
| color k; | |
| float g; | |
| Mover() { | |
| loc = new PVector(random(width),random(height)); | |
| vel = new PVector(0, 0); | |
| mass = random (0.1,0.5); | |
| acc = new PVector(0,0); | |
| rad = mass*20; | |
| k = color (0); | |
| initForce = new PVector(random(-0.002,0.002),random(-0.002,0.002)); //give the mover an initial velocity | |
| maxSpeed = 3; //speed to which to limit the mover's velocity | |
| maxForce = 0.05; //maximum force steering force to be applied | |
| g = 50; //gravitational constant | |
| } | |
| void update() { | |
| vel.add(acc); | |
| vel.limit(maxSpeed); //limit the velocity of the mover | |
| loc.add(vel); | |
| acc.mult(0); //reset the acceleration at the end of every frame | |
| } | |
| void applyForce(PVector force) { | |
| PVector f = PVector.div(force, mass); //creace a copy of the original force | |
| acc.add(f); | |
| } | |
| void display() { | |
| float theta = vel.heading() + PI/2; //the triangle is drawn upright, so rotate by 90degrees | |
| fill(k); | |
| //draw the triangle for the mover | |
| pushMatrix(); | |
| translate(loc.x,loc.y); | |
| rotate(theta); | |
| beginShape(); | |
| vertex(0, -rad*1.3); | |
| vertex(-rad, rad*1.3); | |
| vertex(rad, rad*1.3); | |
| endShape(CLOSE); | |
| popMatrix(); | |
| noFill(); | |
| k = 0; //reset the colour to black at the end of every frame, this ensures | |
| //that the colour changes back to black when the movers leave the patch. | |
| } | |
| // ellipse(loc.x,loc.y,rad*2,rad*2); | |
| // k = 0; | |
| void checkEdges(){ | |
| if (loc.x < 0){ | |
| loc.x += width; | |
| } else if (loc.x > width){ | |
| loc.x -= width; | |
| } | |
| if (loc.y < 0){ | |
| loc.y += height; | |
| } else if (loc.y > height){ | |
| loc.y -= height; | |
| } | |
| } | |
| void seek(PVector target){ | |
| //create a new vector by subtracting the mover's location from the mouse's location | |
| //this is the direction in which the mover "would like to travel" | |
| PVector desired = PVector.sub(target,loc); | |
| desired.setMag(maxSpeed); //set the magnitude according to the predefined maxspeed variable | |
| //create a new vector by subtracting the desired location from the current | |
| //velocity. The resultant force will steer the mover toward the target location | |
| PVector steer = PVector.sub(desired,vel); | |
| steer.limit(maxForce); //limit the magnitude of the resultant vector for smoother/ more realistic motion | |
| applyForce(steer); | |
| } | |
| //the repel method causes the mover to apply a repulsion force to every mover in | |
| //the environment | |
| PVector repel(Mover m){ | |
| PVector force = PVector.sub(loc,m.loc); //create a copy of the vector and get the direction | |
| float d = force.mag(); //get the magnitude of the computed vector | |
| //d = constrain(d,5.0,25.0); | |
| force.normalize(); //reduce it to a unit vector | |
| force.mult(-1); //reverse the direction for a repulsive force | |
| //the force strenght is determined by the universal strength of attraction | |
| float strength = (g * mass * m.mass) / (d * d); | |
| force.mult(strength); //multiply the unit vector by the computed strength | |
| return force; | |
| } | |
| } | |
| class Patch{ | |
| float rad; | |
| PVector loc; //PVector to store the objects location | |
| float c; //co-efficient of drag | |
| Patch(){ | |
| rad = random(10,75); //assign a random radius | |
| loc = new PVector(random(width),random(height)); //draw the patch in a random location | |
| c = random(0.01,0.05); //initialise it to a random value | |
| } | |
| //pass patch p into the function | |
| PVector calcDrag(Mover m){ | |
| float speed = m.vel.mag(); //speed is the scalar value of the mover's velocity | |
| float dragMag = c*speed*speed; //the magnitude of the drag force is equivalent to the patch's | |
| //coefficient of friction multiplied by the square of the movers speed | |
| PVector drag = m.vel.get(); //get a copy of the movers direction | |
| drag.normalize(); //normalize to get the unit vector | |
| drag.mult(-1); //reverse the direction | |
| drag.mult(dragMag); //multiply the unit vector by the magnitude of the force | |
| return drag; //apply the new drag force to 'this' mover | |
| } | |
| boolean isInside(Mover m){ | |
| PVector l = m.loc; | |
| float d = dist(loc.x,loc.y,l.x,l.y); | |
| //if the distance between the centers is less than the sum of the radii | |
| //the mover must be inside the patch | |
| if (d < rad + m.rad){ | |
| return true; | |
| } else { | |
| return false; | |
| } | |
| } | |
| void display(){ | |
| fill(0,20); | |
| noStroke(); | |
| ellipse(loc.x,loc.y,rad*2,rad*2); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment