Tutorials
(back to the list of tutorials)
Multi-Agent Algorithm: Inter-Class Interaction
(requires iGeo version 7.4.0 or higher)
 
Agents and Attractors
In this section, techniques to use interaction of different classes is shown. You can define a specific role to each of different classes to have composite behavior in multi-agent system.
To control a large number of agents, an attractor is often introduced. You define attractors to be located somewhere in the space and agents are oriented towards the location of the attractor.
import processing.opengl.*;
import igeo.*;
void setup(){
size(480,360,IG.GL);
IG.duration(500);
for(int i=0; i < 3; i++){
new MyAttractor(IRand.pt(0, 0, 20, 100, 100, 20));
}
//agents in a matrix
for(int i=0; i < 10; i++){
for(int j=0; j < 10; j++){
new MyLineAgent(new IVec(i*10, j*10, 0),
new IVec(0,0,0.5)).clr(.5,i*0.1,j*0.1);
}
}
}
static class MyAttractor extends IAgent{
IVec pos;
IPoint point;
MyAttractor(IVec p){
pos = p;
point = new IPoint(pos).clr(1.0,0,0);
}
void update(){
// random walk
pos.add(IRandom.pt(-5,5));
}
}
static class MyLineAgent extends IAgent{
IVec pos, dir;
MyLineAgent(IVec p, IVec d){
pos = p;
dir = d;
}
void interact(ArrayList < IDynamics > agents){
//searching the closest attractor
MyAttractor closestAttractor=null;
double minDist=-1;
for(int i=0; i < agents.size(); i++){
if(agents.get(i) instanceof MyAttractor){
MyAttractor attractor = (MyAttractor)agents.get(i);
double dist = attractor.pos.dist(pos);
//first attractor to check
if(minDist < 0){
closestAttractor = attractor;
minDist = dist;
}
//if less than minimum, it's new minimum
else if(dist < minDist){
closestAttractor = attractor;
minDist = dist;
}
}
}
//in case no attractor found, if-condition is used
if(closestAttractor!=null){
IVec diff = closestAttractor.pos.diff(pos);
diff.len(dir.len());
dir = diff;
}
}
void update(){
new ICurve(pos.dup(), pos.dup().add(dir)).clr(clr());
pos.add(dir);
}
}
One important part of the code is the code to find the closest attractor out of multiple attractors in the space. This is a typical algorithm to search data in array of data. You use for loop to check all the data and prepare value to be searched outside of the for-loop. The prepared values on this code are closestAgent and minDist.
Inside for-loop, you need to initialize
those value when they are accessed for the first time.
Because minDist is initialized with -1, and
because any distance is positive number,
you can check if it's the first time or not by
 
Simple Boundary of Agents
import processing.opengl.*;
import igeo.*;
void setup(){
size(480, 360, IG.GL);
IG.duration(1000);
new MyBoundary(-200,-200,200,200);
new MyHexAgent(new IVec(0,0,0), new IVec(0,10,0));
}
class MyBoundary extends IAgent{
double minx, maxx, miny, maxy;
MyBoundary(double x1, double y1, double x2, double y2){
minx = x1;
miny = y1;
maxx = x2;
maxy = y2;
IG.rect(new IVec(minx, miny, 0), maxx-minx, maxy-miny);
}
}
class MyHexAgent extends IAgent{
IVec pos, dir;
double depth=0, depthInc=0.5, hue=0;
MyHexAgent(IVec p, IVec d){ pos = p; dir = d; }
void interact( ArrayList < IDynamics > agents ){
for(int i=0; i < agents.size(); i++){
if(agents.get(i) instanceof MyBoundary){
MyBoundary boundary = (MyBoundary)agents.get(i);
//checking if next position is out of the boundary
IVec nextPos = pos.cp(dir);
if(nextPos.x < boundary.minx){
dir.ref(IG.xaxis); //reflect on x-plane
}
else if(nextPos.x > boundary.maxx){
dir.ref(IG.xaxis); //reflect on x-plane
}
if(nextPos.y < boundary.miny){
dir.ref(IG.yaxis); //reflect on y-plane
}
else if(nextPos.y > boundary.maxy){
dir.ref(IG.yaxis); //reflect on y-plane
}
}
}
}
void update(){
createHexGeometry();
pos.add(dir);
//random shift of direction
if(IRand.percent(10)){ dir.rot(IG.zaxis,PI/3); }
else if(IRand.percent(10)){ dir.rot(IG.zaxis,-PI/3); }
//random shift of height
if(IRandom.percent(10)){ depthInc *= -1; }
depth += depthInc;
hue += 0.002;
}
void createHexGeometry(){
//creating hexagonal extrusion
IVec[] cpts = new IVec[6];
for(int i=0; i<6; i++){
cpts[i] =
dir.dup().rot(IG.zaxis,PI/3*i+PI/6).div(2).add(pos);
}
IG.extrude(cpts, 1, true, depth).hsb(hue,1,1);
}
}
 
Blocking Agents
import processing.opengl.*;
import igeo.*;
void setup(){
size(480, 360, IG.GL);
IG.duration(150);
new LineAgent(new IVec(0,0,0), new IVec(1,0,0));
for(int i=-1; i<=1; i+=2){
for(int j=-1; j<=1; j+=2){
for(int k=-1; k<=1; k+=2){
new LineBlockAgent(new IVec(40*i,40*j,40*k), 40);
}
}
}
}
static class LineBlockAgent extends IAgent{
IVec pos;
double radius;
LineBlockAgent(IVec p, double rad){
pos = p; radius = rad;
}
void interact(ArrayList < IDynamics > agents){
super.interact(agents);
for(int i=0; i < agents.size(); i++){
if(agents.get(i) instanceof LineAgent){
LineAgent lineAgent = (LineAgent)agents.get(i);
if(lineAgent.pt2.dist(pos) < radius){
lineAgent.del();
}
}
}
}
void update(){
super.update();
if(time==0){ new ISphere(pos,radius).clr(0,1,1,0.0); }
}
}
static class LineAgent extends IAgent{
static double length = 2;
static double clearance = 1.99; //less than length
IVec pt1, pt2;
boolean isColliding=false;
LineAgent(IVec pt, IVec dir){
pt1 = pt;
pt2 = pt.dup().add(dir.dup().len(length));
}
void interact(ArrayList < IDynamics > agents){
super.interact(agents);
if(time == 0){ //only in the first time
for(int i=0; i < agents.size() && !isColliding; i++){
if(agents.get(i) instanceof LineAgent){
LineAgent lineAgent =
(LineAgent)agents.get(i);
if(lineAgent != this){ //agents include "this"
// checking clearance of end point
if(lineAgent.pt2.dist(pt2) < clearance){
isColliding=true;
}
}
}
}
}
}
void update(){
super.update();
if(isColliding){
del();
}
else if(time == 0){ //if not colliding
new ICurve(pt1,pt2).clr(0);
IVec dir = pt2.diff(pt1);
//rotation axis with random direction
IVec axis = IRandom.pt(-1,1).len(1);
if(IRandom.percent(50)){ //bend
new LineAgent(pt2, dir.dup().rot(axis,
IRandom.get(PI/3,PI/3*2)));
}
if(IRandom.percent(50)){ //bend the other way
new LineAgent(pt2, dir.dup().rot(axis,
-IRandom.get(PI/3,PI/3*2)));
}
if(IRandom.percent(90)){ //straight
new LineAgent(pt2, dir.dup());
}
}
}
}
HOME
FOR PROCESSING
DOWNLOAD
DOCUMENTS
TUTORIALS
GALLERY
SOURCE CODE(GitHub)
ABOUT