Processing: Autonomous Steering Behaviours: Part 01

Definitions
SWARM “to mean any loosely structured collection of agents that interact with one another.
Kennedy, James. Eberhart, Russel C. Swarm Intelligence.
AGENTS “refers to an object in a computer program that has an identity and performs some actions, usually with some presumption that the activities of the agent are somewhat autonomous or independent of the activities of the other agents.”
Kennedy, James. Eberhart, Russel C. Swarm Intelligence.
EMERGENCE “the movement from low-level rules to higher-level sophistification”
Johnson, Stephen. Emergence: The Conected Lives of Ants, Brains, Cities and Software.
Introduction
Agent systems are time-based networks driven by simple, highly local and individually motivated rules pertaining to the interaction of objects – deliberately coined agents – as opposed to particles – to exaggerate their programmed or embedded intelligences. The most common examples usually given of such systems are those of bird flocks, ant colonies, and swarms of bees. An agent moves through space motivated by its own desire (velocity), stimulated by goal seeking (attractors, targets, etc..) and is also informed by the presence of fellow members of the population at a local level. It is this latter aspect which gives large populations of agents a collective body as the agents make “steering” decisions based upon the presence, speed and direction of any neghbours who may fall within a range of perception (sight, smell, etc…). These steering behaviours were largely pioneered by Craig Reynolds who has long demonstrated that 3 simple steering behaviors are sufficient for a computer model to exhibit swarm-like character. These behaviors are separation, alignment and cohesion. For further reading on steering behaviours, see:
Dan Shiffman has also written an excellant introduction to steering behaviours in Processing. Indeed he has an excellant teaching page in general for all things Processing. To learn more visit:
Prior to reading on, it is assumed that you have already read the tutorials on Object Orientated Programming and those pertaining to particle systems. If you have not done so, then it is best to review these prior to proceeding!
Applying Steering Forces
As we have already seen through dealing with the application of forces on particles, an agent is defined by three vectors; its position or coordinate in space (x,y,z), its velocity (x,y,z) which describes both its heading and speed, and finally its acceleration (x,y,z) at each time frame. And again as we have previously seen, the future position of the agent is simply calculated by adding its current velocity to its current position. The acceleration of an agent is the sum of all external and internal forces over and above its velocity. In the example of agent steering it may be the effect of goal seeking (steering toward a target), or the influence of swarm or collective behaviour. We shall deal with population-based steering behaviours later, but essentially the process is the same as we need to calculate the forces of acceleration each time step, add them to the velocity and reset the acceleration to zero prior to the next time step.
To do so, we first need a function that we can call each iteration to update the agents position. It will look like this:
void run(SuperWorld WORLD){ // calculate acceleration forces acc = blah, blah, blah, blah, blah...... // calculate the acceleration forces // 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 render(); // draw the agent! }
Steering Function
The first function we shall write is a steering function so that we may steer our agents toward a target or attractor. The steering function receives 3 arguments, a target, a dimensional range, and a third boolean argument called slowDown. The following is modelled after Dan Shiffman’s example (hence the argument name). The slowDown argument allows (when TRUE) the agent to arrive at its target, ie, reduce speed and effectively hover at the target. If the slowDown is not activated (FALSE), the agent will overshoot the target, and appear something like a moth buzzing around a light source. The steer function returns a force (vector) which we then need to add to the agents acceleration in order for any effect to take place. The best way to do this is via a function which handles both the input and output of the steer function – seek.
//-------------------------------------------------------------SEEK TARGET void seek(PVector target, float threshold){ acc.add( steer(target,threshold, true) ); } //------------------------------------------------------------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; }

Example 01: Seeking a Target
/*------------------------------------------------------------------------------------------------- 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 = 10; int ENVX = 500; // size of the environment in the X direction int ENVY = 500; // 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(); // Pass the population of agents to the agent! } } /*------------------------------------------------------------------------------------------------- Agent Class -------------------------------------------------------------------------------------------------*/ class SuperAgent{ // *** CLASS VARIABLES *** PVector pos, vel, acc; float maxVel, maxForce, rangeOfVision; 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); rangeOfVision = 120; // Appearance of agent agentSize = 10; agentColour = 175; } // *** CLASS METHODS *** //----------------------PRIMARY FUNCTION - call all other functions here! void run(){ seek(TARGET.get(), rangeOfVision, true); // Call the agents seek function and be sure to pass the correct numebr of arguments! // 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! } //---------------------- 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; } //----------------------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) ); } }
You’re currently reading “Processing: Autonomous Steering Behaviours: Part 01”, an entry on supermanoeuvre
- Published:
- 25.06.09 / 2am
- Category:
- Processing, Tutorials, Uncategorized
- Tags:
Comments are closed
Comments are currently closed on this entry.