Processing: Autonomous Steering Behaviours – Part 02

Swarm Behaviour – Population-Based Steering
To establish a life-like swarm behaviour we need to write some functions that calculate the steering forces described by Craig Reynolds. These functions will be called each iteration of the simulation and the results added to the acceleration of the agent at each time step. We shall break down each of these functions one-by-one, however it may be easier to move to the completed example beow to see how agent class is structured as an overall to get a better understanding.
void update2Pop(ArrayList POP){ // calculate steering forces based on population PVector sep = separate(POP); // separate PVector ali = alignment(POP); // alignment PVector coh = cohesion(POP); // cohesion // arbitary weighting of these forces sep.mult(sepScale); ali.mult(aliScale); coh.mult(cohScale); // add the force vectors to acceleration acc.add(sep); acc.add(ali); acc.add(coh); }

Separation
Separation applies a lateral steering force that results in the agent avoiding its neighbours, or if you like it effectively prevents overcrowding! The calculation is based on a weighted assessment of each agents neighbours, or population members who are within a given range (sight, smell, etc…). Generally we use the same range variable for all steering behaviours, however we decreaset he range of separation to ensure that cohesion can occur, before separation kicks in to stop excessive bunching.
PVector separate(ArrayList POP){ PVector sum = new PVector(0,0,0); int count = 0; for (int i = 0; i < POP.size(); i++){ SuperAgent other = (SuperAgent) POP.get(i); // get is a method of ArrayClass() in Java float distance = pos.dist(other.pos); // use kVec.distance() // if distance > 0 and distance < range of vison (is in sight!?) if ((distance > 0) && (distance < rangeOfVision/3)){ // calculate vector pointing away from neighbour PVector diff = pos.get(); diff.sub(other.pos); diff.normalize(); diff.mult(1/distance); // weight by distance sum.add(diff); // add to create new position count++; } } // average -- divide by how many in range if (count > 0){ sum.mult(1/(float)count); } return sum; }

Alignment
Alignment is the averaging of all the headings (velocities) of an agents population within a given range (sight, smell, etc…). The result of alignment is that the population begins to flow in a similar manner, resulting in a more recognisable behavioural pattern.
PVector align(ArrayList POP){ PVector sum = new PVector(0,0,0); int count = 0; for (int i = 0; i < POP.size(); i++) { SuperAgent other = (SuperAgent) POP.get(i); float distance = pos.dist(other.pos); if ((distance > 0) && (distance < rangeOfVision)) { sum.add(other.vel); count++; } } if (count > 0){ sum.mult(1/(float)count); sum.limit(maxForce); } return sum; }

Cohesion
Cohesion is a steering force toward the average position of all the population members within range (sight, smell, etc…).
PVector cohesion(ArrayList POP){ PVector sum = new PVector(0,0,0); int count = 0; for (int i = 0; i < POP.size(); i++){ SuperAgent other = (SuperAgent) POP.get(i); // get is a method of ArrayClass() in Java float distance = pos.dist(other.pos); // use kVec.distance() if ((distance > 0) && (distance < rangeOfVision)){ sum.add(other.pos); // add to create new position count++; } } if (count > 0){ sum.mult(1/(float)count); return steer(sum,rangeOfVision, true); } return sum; }

Example 01: A simple 2D swarm
/*------------------------------------------------------------------------------------------------- Declare our variables -------------------------------------------------------------------------------------------------*/ ArrayList agents; // an arraylist to store all of our agents! PVector TARGET; // The target will be the current position of the mouse! int numAgents = 25; int ENVX = 600; // size of the environment in the X direction int ENVY = 250; // size of the environment in the Y direction /*------------------------------------------------------------------------------------------------- Setup Sketch -------------------------------------------------------------------------------------------------*/ void setup(){ size(ENVX,ENVY, P3D); // set the applet size to desired environment background(0); // set the applet background to black ellipseMode(CENTER); agents = new ArrayList(); // make our arraylist to store our agents TARGET = new PVector(ENVX/2, ENVY/2, 0); // make a starting target // loop to make our agents! for(int i = 0; i < numAgents; i++){ agents.add( new SuperAgent() ); } } /*------------------------------------------------------------------------------------------------- Draw Loop -------------------------------------------------------------------------------------------------*/ void draw(){ background(0); // Set the applet background to black TARGET = new PVector(mouseX, mouseY, 0); // if mouse is pressed then update target for(int i = 0; i < agents.size(); i++){ SuperAgent A = (SuperAgent) agents.get(i); A.run(agents); // Pass the population of agents to the agent! } if(keyPressed) saveFrame("swarm_###.jpg"); // screen capture } /*------------------------------------------------------------------------------------------------- Agent Class -------------------------------------------------------------------------------------------------*/ class SuperAgent{ // *** CLASS VARIABLES *** PVector pos, vel, acc; float maxVel, maxForce, rangeOfVision, cohScale, aliScale, sepScale; int agentSize, agentColour; // *** CLASS CONSTRUCTOR *** SuperAgent(){ // 3 vectors to describe agents position, heading & speed pos = new PVector( random(0,width), random(0,height), 0 ); vel = new PVector( random(-1,1), random(-1,1), 0 ); acc = new PVector(0,0,0); // max speed and steering force variables maxVel = random(1.5, 3.0); maxForce = random(0.2, 0.5); // steering force variables cohScale = 1.0; aliScale = 1.0; sepScale = 16.0; rangeOfVision = 50.0; // Appearance of agent agentSize = 10; agentColour = 175; } // *** CLASS METHODS *** //--------------------------------------------------------PRIMARY FUNCTION - call all other functions here! void run(ArrayList POP){ // update population based steering updateSteering(POP); // update position vel.add(acc); // add the acceleration to the velocity vel.limit(maxVel); // clip the velocity to a maximum allowable pos.add(vel); // add velocity to position acc.set(0,0,0); // make sure we set acceleration back to zero! // standard update functions toroidalBorders(); // wrap around screen - agent leaves on the left and returns on the right! render(); // draw the agent! } //--------------------------------------------------------UPDATE STEERING void updateSteering(ArrayList POP){ // calculate the steering forces PVector coh = cohesion(POP); PVector sep = separation(POP); PVector ali = alignment(POP); // scale the steering forces coh.mult(cohScale); sep.mult(sepScale); ali.mult(aliScale); // add to acceleration acc.add(coh); acc.add(sep); acc.add(ali); } //--------------------------------------------------------WRAP AROUND SCREEN - KEEP AGENTS ON THE SCREEN void toroidalBorders(){ if(pos.x < 0 ) pos.x = ENVX; if(pos.x > ENVX) pos.x = 0; if(pos.y < 0 ) pos.y = ENVY; if(pos.y > ENVY) pos.y = 0; } //--------------------------------------------------------DRAW THE AGENT void render(){ stroke(agentColour); fill(agentColour,90); // put a circle on the agents position ellipse(pos.x,pos.y, agentSize, agentSize); // draw the heading of the agent line(pos.x, pos.y, pos.x+(vel.x*agentSize), pos.y+(vel.y*agentSize) ); } // *** STEERING BEHAVIOURS *** //--------------------------------------------------------SEEK TARGET void seek(PVector target, float threshold, boolean slowDown){ acc.add( steer(target,threshold, slowDown) ); } //--------------------------------------------------------STEER PVector steer (PVector target, float threshold, boolean slowDown ){ PVector steerForce; // The steering vector target.sub(pos); float d2 = target.mag(); if ( d2 > 0 && d2 < threshold){ target.normalize(); if( (slowDown) && d2 < threshold/2 ) target.mult( maxVel * (threshold/ENVX) ); else target.mult(maxVel); target.sub(vel); steerForce = target.get(); steerForce.limit(maxForce); } else { steerForce = new PVector(0,0,0); } return steerForce; } //--------------------------------------------------------SEPARATE PVector separation(ArrayList POP){ PVector sum = new PVector(0,0,0); int count = 0; for (int i = 0; i < POP.size(); i++){ SuperAgent other = (SuperAgent) POP.get(i); // get is a method of ArrayClass() in Java float distance = pos.dist(other.pos); // use kVec.distance() // if distance > 0 and distance < range of vison (is in sight!?) if ((distance > 0) && (distance < rangeOfVision/3)){ // calculate vector pointing away from neighbour PVector diff = pos.get(); diff.sub(other.pos); diff.normalize(); diff.mult(1/distance); // weight by distance sum.add(diff); // add to create new position count++; } } // average -- divide by how many in range if (count > 0){ sum.mult(1/(float)count); } return sum; } //--------------------------------------------------------ALIGNMENT PVector alignment(ArrayList POP){ PVector sum = new PVector(0,0,0); int count = 0; for (int i = 0; i < POP.size(); i++) { SuperAgent other = (SuperAgent) POP.get(i); float distance = pos.dist(other.pos); if ((distance > 0) && (distance < rangeOfVision)) { sum.add(other.vel); count++; } } if (count > 0){ sum.mult(1/(float)count); sum.limit(maxForce); } return sum; } //--------------------------------------------------------COHESION PVector cohesion(ArrayList POP){ PVector sum = new PVector(0,0,0); int count = 0; for (int i = 0; i < POP.size(); i++){ SuperAgent other = (SuperAgent) POP.get(i); // get is a method of ArrayClass() in Java float distance = pos.dist(other.pos); // use kVec.distance() if ((distance > 0) && (distance < rangeOfVision)){ sum.add(other.pos); // add to create new position count++; } } if (count > 0){ sum.mult(1/(float)count); return steer(sum,rangeOfVision, true); } return sum; } }
You’re currently reading “Processing: Autonomous Steering Behaviours – Part 02”, an entry on supermanoeuvre
- Published:
- 15.06.09 / 8am
- Category:
- Processing, Tutorials, Uncategorized
- Tags:
- Post Navigation:
- « Processing 05: Physical forces & motion
Processing: Cellular Automata »
Comments are closed
Comments are currently closed on this entry.