Tutorials | (back to the list of tutorials) |
Multi-Agent 2D Example 3 (requires iGeo version 7.5.1 or higher)![]()
![]()
![]()
![]()
import processing.opengl.*;
import igeo.*;
void setup() {
size(480, 360, IG.GL);
IG.duration(700);
// left 99.0%, right 1.5%
new LineAgent(IG.v(0,0,0), IG.v(2,0,0), 99.0, 1.5).clr(0);
}
static class LineAgent extends IAgent{
IVec pos;
IVec dir;
double pctL, pctR;
LineAgent(IVec pt, IVec dir, double pctL, double pctR) {
pos = pt;
this.dir = dir;
this.pctL = pctL;
this.pctR = pctR;
}
public void update() {
if(time()==0){
//putting line geometry
IVec pos2 = pos.dup().add(dir);
new ICurve(pos, pos2).clr(clr());
double r = red() + IRand.get(-0.05, 0.05);
double g = green() + IRand.get(-0.05, 0.05);
double b = blue() + IRand.get(-0.05, 0.05);
if(IRand.pct(3.0)){ //swap L/R percent
double tmp = pctL;
pctL = pctR;
pctR = tmp;
}
if (IRand.pct(pctL)) { //bend left
IVec dir2 = dir.dup();
dir2.rot(PI/30);
new LineAgent(pos2, dir2, pctL, pctR).clr(r,g,b);
}
if (IRand.pct(pctR)) { //bend right
IVec dir2 = dir.dup();
dir2.rot(-PI/30);
new LineAgent(pos2, dir2, pctL, pctR).clr(r,g,b);
}
del();
}
}
}
The next code adds interact() method to the previous code to detect collision of line agents. A line agent stops when it collides into other existing agents. Then the algorithm to swap left and right probability is also changed to swap them only when an agent creates a new branch.
![]()
![]()
![]()
![]()
import processing.opengl.*;
import igeo.*;
void setup() {
size(480, 360, IG.GL);
IG.duration(350);
// left 99.0%, right 7.0%
new LineAgent(IG.v(0,0,0), IG.v(2,0,0), 99.0, 7.0).clr(0);
}
static class LineAgent extends IAgent{
IVec pos;
IVec dir;
double pctL, pctR;
boolean isColliding=false;
LineAgent(IVec pt, IVec dir, double pctL, double pctR) {
pos = pt;
this.dir = dir;
this.pctL = pctL;
this.pctR = pctR;
}
public void interact(ArrayList agents){
if(time()==0){
for(int i=0; i < agents.size() && !isColliding ; i++){
if(agents.get(i) instanceof LineAgent){
LineAgent a = (LineAgent)agents.get(i);
if(a != this){
if(a.pos.dist(pos.cp(dir)) < dir.len()*0.999){
isColliding=true;
}
}
}
}
}
}
public void update() {
if(time()==0){
if(isColliding){ del(); return; }
//putting line geometry
IVec pos2 = pos.dup().add(dir);
new ICurve(pos, pos2).clr(clr());
double r = red() + IRand.get(-0.05, 0.05);
double g = green() + IRand.get(-0.05, 0.05);
double b = blue() + IRand.get(-0.05, 0.05);
boolean branchL = IRand.pct(pctL); //boolean switch L
boolean branchR = IRand.pct(pctR); //boolean switch R
if (branchL) { //bend left
IVec dir2 = dir.dup();
dir2.rot(PI/30);
if(branchR && pctR > pctL){//swap L/R% when branching both
new LineAgent(pos2, dir2, pctR, pctL).clr(r,g,b);
}
else{
new LineAgent(pos2, dir2, pctL, pctR).clr(r,g,b);
}
}
if (branchR) { //bend right
IVec dir2 = dir.dup();
dir2.rot(-PI/30);
if(branchL && pctR < pctL){//swap L/R% when branching both
new LineAgent(pos2, dir2, pctR, pctL).clr(r,g,b);
}
else{
new LineAgent(pos2, dir2, pctL, pctR).clr(r,g,b);
}
}
}
}
}
The code below
changes the length of agent's line at every update.
The lengths of all agents are slightly scaled down
constantly, creating swirling curves.
On top of it, the length is scaled up or down stochastically,
only when the agent is creating a branch.
In intersect() method, the
collision detection algorithm is changed.
It's using the method of
IVec.intersectLine(IVec line1Pt1, IVec line1Pt2, IVec line2Pt1, IVec line2Pt2)
to calculate intersection of two line segments because
the previous algorithm of collision detection wouldn't work
when there are different lengths of lines.
![]()
![]()
![]()
![]()
import processing.opengl.*;
import igeo.*;
void setup() {
size(480, 360, IG.GL);
IG.duration(400);
// left 100%, right 4.5%
new LineAgent(IG.v(0,0,0), IG.v(2,0,0), 100.0, 4.5).clr(0);
}
static class LineAgent extends IAgent{
IVec pos;
IVec dir;
double pctL, pctR;
boolean isColliding=false;
LineAgent(IVec pt, IVec dir, double pctL, double pctR) {
pos = pt;
this.dir = dir;
this.pctL = pctL;
this.pctR = pctR;
}
public void interact(ArrayList agents){
if(time()==0){
for(int i=0; i < agents.size() && !isColliding ; i++){
if(agents.get(i) instanceof LineAgent){
LineAgent a = (LineAgent)agents.get(i);
if(a != this){
IVec pos2 = pos.cp(dir);
IVec apos2 = a.pos.cp(a.dir);
if(!apos2.eq(pos) && !a.pos.eq(pos) && //not sharing root
IVec.intersectLine(a.pos,apos2,pos,pos2)!=null){ //intersecting
isColliding=true;
}
}
}
}
}
}
public void update() {
if(time()==0){
if(isColliding){ del(); return; }
IVec pos2 = pos.dup().add(dir);
new ICurve(pos, pos2).clr(clr());
double r = red() + IRand.get(-0.05, 0.05);
double g = green() + IRand.get(-0.05, 0.05);
double b = blue() + IRand.get(-0.05, 0.05);
boolean branchL = IRand.pct(pctL);
boolean branchR = IRand.pct(pctR);
double lenL = dir.len();
double lenR = dir.len();
lenL*=0.995; //shrinking length
lenR*=0.995; //shrinking length
if (branchL && branchR) { //only when branching both
if(IRand.pct(50.0)){
if (pctL < pctR) { lenL *= 0.9; }
else{ lenR *= 0.9; }
}
else if(IRand.pct(6.0)){
if (pctL < pctR) { lenL *= 0.4; }
else{ lenR *= 0.4; }
}
else if(IRand.pct(5.0)){
if (pctL < pctR) { lenL *= 4.0; }
else{ lenR *= 4.0; }
}
}
if (branchL) { //bend left
IVec dir2 = dir.dup();
dir2.len(lenL); //update length
dir2.rot(PI/30);
if(branchR && pctR > pctL){//swap L/R% when branching both
new LineAgent(pos2, dir2, pctR, pctL).clr(r,g,b);
}
else{
new LineAgent(pos2, dir2, pctL, pctR).clr(r,g,b);
}
}
if (branchR) { //bend right
IVec dir2 = dir.dup();
dir2.len(lenR); //update length
dir2.rot(-PI/30);
if(branchL && pctR < pctL){//swap L/R% when branching both
new LineAgent(pos2, dir2, pctR, pctL).clr(r,g,b);
}
else{
new LineAgent(pos2, dir2, pctL, pctR).clr(r,g,b);
}
}
}
}
}
HOME
FOR PROCESSING
DOWNLOAD
DOCUMENTS
TUTORIALS (Java /
Python)
GALLERY
SOURCE CODE(GitHub)
PRIVACY POLICY
ABOUT/CONTACT