home processing download documents tutorial python tutorial gallery source about
 Python Tutorials (back to the list of tutorials)

Multi-Agent 2D Examples

     Multi-Agent 2D Example 4

The following example shows a line agent which turns when it finds another line agent in front of it. It turns into the parallel direction of the another agent and it turns only left, not right. In its interact method, the agent searches the closest other agent in front within the threshold range and measures the angle of the other agent. This angle is stored in frontAngle and this is used to rotate the agent in the update method.

add_library('igeo')

def setup() : 
    size(480,360,IG.GL)
    IRand.init(3)
    IG.duration(700)
    LineAgent(IG.v(-0.1,0,0), IG.v(1,0,0)).clr(0)
    LineAgent(IG.v(500,-0.1,0), IG.v(0,1,0)).clr(0)
    LineAgent(IG.v(500+0.1,500,0), IG.v(-1,0,0)).clr(0)
    LineAgent(IG.v(0,500+0.1,0), IG.v(0,-1,0)).clr(0)
    
    for i in range(10) : 
        LineAgent(IRand.pt(100,100,0,400,400,0), IRand.pt(-10,-10,0,10,10,0)).clr(IRand.clr(0.4,0.4,0.4))

class LineAgent(IAgent) : 
    # static variable constants
    length = 2
    clearance = 1.99 #less than length
    angleThreshold = PI/20
    threshold = 10
    
    def __init__(self, pt, dir) : 
        self.pt1 = pt
        self.pt2 = pt.cp(dir.cp().len(LineAgent.length))
        self.isColliding = False
        self.angle = 0
        self.minDist = 0
        self.frontAngle = 0
    
    def interact(self, agents) :
        if self.time() == 0 : #only in the first time
            self.minDist = -1 #reset
            for agent in agents : 
                if self.isColliding :
                    return
                if isinstance(agent, LineAgent) and agent is not self : 
                    # checking clearance of end point
                    dist = agent.pt2.dist(self.pt2)
                    if dist < LineAgent.clearance :
                        self.isColliding=True
                    elif dist < LineAgent.threshold : #not colliding but close
                        #check if not the parent and in front and closest one
                        if not self.pt1.eq(agent.pt2) and \
                           self.pt2.dif(self.pt1).angle(agent.pt2.dif(self.pt1)) < LineAgent.angleThreshold and \
                           (self.minDist < 0 or dist < self.minDist) : 
                            self.minDist = dist
                            self.frontAngle = self.pt2.dif(self.pt1).angle(agent.pt2.dif(agent.pt1),IG.zaxis)
    
    def update(self) :
        if self.time() == 0 :
            if self.isColliding : 
                self.del()
            else : #if not colliding
                ICurve(self.pt1,self.pt2).clr(self.clr())
                dir = self.pt2.dif(self.pt1)
                if IRand.pct(1) : #branching
                    r = self.red()+IRand.get(-0.1,0.1)
                    g = self.green()+IRand.get(-0.1,0.1)
                    b = self.blue()+IRand.get(-0.1,0.1)
                    LineAgent(self.pt2, dir.cp().rot(IRand.get(PI/3,2*PI/3))).clr(r,g,b)
                
                if self.frontAngle < 0 : 
                    self.frontAngle+=PI #going in only one direction
                r = self.red()+IRand.get(-0.03,0.03)
                g = self.green()+IRand.get(-0.03,0.03)
                b = self.blue()+IRand.get(-0.03,0.03)
                LineAgent(self.pt2, dir.rot(self.frontAngle)).clr(r,g,b)

The next code change the previous code to round the turning corner by bending the lines with a few segments. To enable bending through multiple generation of agents, the instance field of bendAngle and bendCount are added to LineAgent class.

add_library('igeo')

def setup() : 
    size(480,360,IG.GL)
    IRand.init(2)
    IG.duration(700)
    LineAgent(IG.v(-0.1,0,0),IG.v(1,0,0),0,0).clr(0)
    LineAgent(IG.v(500,-0.1,0),IG.v(0,1,0),0,0).clr(0)
    LineAgent(IG.v(500+0.1,500,0),IG.v(-1,0,0),0,0).clr(0)
    LineAgent(IG.v(0,500+0.1,0),IG.v(0,-1,0),0,0).clr(0)
    
    LineAgent(IG.v(500/2,0,0),IG.v(1,0,0),0,0).clr(0)
    LineAgent(IG.v(500,500/2,0),IG.v(0,1,0),0,0).clr(0)
    LineAgent(IG.v(500/2,500,0),IG.v(-1,0,0),0,0).clr(0)
    LineAgent(IG.v(0,500/2,0),IG.v(0,-1,0),0,0).clr(0)
    
    for i in range(30) : 
        LineAgent(IRand.pt(100,100,0,400,400,0),IRand.pt(-10,-10,0,10,10,0),0,0).clr(IRand.clr(0.4,0.4,0.4))

class LineAgent(IAgent) : 
    # static variable constants
    length = 2
    clearance = 1.99 #less than length
    angleThreshold = PI/20
    threshold = 10
    bendSize = 2
    
    def __init__(self, pt, dir, bend, bcount) :
        self.pt1 = pt
        self.pt2 = pt.cp(dir.cp().len(LineAgent.length))
        self.isColliding = False
        self.minDist = 0
        self.frontAngle = 0
        self.bendAngle = bend
        self.bendCount = bcount
    
    def interact(self, agents) :
        if self.time() == 0 : #only in the first time
            self.minDist = -1 #reset
            for agent in agents : 
                if self.isColliding :
                    return
                if isinstance(agent, LineAgent) and agent is not self : 
                    # checking clearance of end point
                    dist = agent.pt2.dist(self.pt2)
                    if dist < LineAgent.clearance :
                        self.isColliding=True
                    elif dist < LineAgent.threshold : #not colliding but close
                        #check if not the parent and in front and closest one
                        if not self.pt1.eq(agent.pt2) and \
                           self.pt2.dif(self.pt1).angle(agent.pt2.dif(self.pt1)) < LineAgent.angleThreshold and \
                           (self.minDist < 0 or dist < self.minDist) : 
                            self.minDist = dist
                            self.frontAngle = self.pt2.dif(self.pt1).angle(agent.pt2.dif(agent.pt1),IG.zaxis)

    def update(self) :
        if self.time() == 0 :
            if self.isColliding :
                self.del()
            else : #if not colliding
                ICurve(self.pt1,self.pt2).clr(self.clr())
                dir = self.pt2.dif(self.pt1)
                if IRand.pct(1) : #branching
                    r = self.red()+IRand.get(-0.1,0.1)
                    g = self.green()+IRand.get(-0.1,0.1)
                    b = self.blue()+IRand.get(-0.1,0.1)
                    LineAgent(self.pt2,dir.cp().rot(IRand.get(PI/3,2*PI/3)),0,0).clr(r,g,b)
                
                r = self.red()+IRand.get(-0.03,0.03)
                g = self.green()+IRand.get(-0.03,0.03)
                b = self.blue()+IRand.get(-0.03,0.03)
                #checking bend
                if self.bendCount == 0 and self.minDist >=0 and self.frontAngle!=0 :
                    if self.frontAngle < 0 : 
                        self.frontAngle+=PI #going in only one direction
                    self.bendCount = LineAgent.bendSize
                    self.bendAngle = self.frontAngle/self.bendCount
                
                if self.bendCount > 0 : #bending
                    dir.rot(self.bendAngle)
                    LineAgent(self.pt2, dir, self.bendAngle, self.bendCount-1).clr(r,g,b)
                else : #go straight
                     LineAgent(self.pt2, dir, 0, 0).clr(r,g,b)


(back to the list of tutorials)

HOME
FOR PROCESSING
DOWNLOAD
DOCUMENTS
TUTORIALS (Java / Python)
GALLERY
SOURCE CODE(GitHub)
ABOUT