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

Making A Custom Agent (Particle Base) (requires iGeo version 0.8.1.9 or higher)

     Particle Based Agent

This tutorial shows a process to develop a custom agent class based on particle behaviors. When you develop a particle-based agent, you can create a class inheriting IParticle class (or IBoid class if you use the swarm behaviors). The following code would be a template to start your custom particle-based agent.

add_library('igeo')

def setup() : 
    size(480,360,IG.GL)
    MyParticle(IVec(0,0,0), IVec(10,0,0))

class MyParticle(IParticle) : 
    def __init__(self, p, v) : 
        IParticle.__init__(self,p,v) # initialize with position and velocity

The code above shows just one moving particle. If you want to show a trajectory of a particle, you can use IParticleTrajectory instead of IParticle.

add_library('igeo')

def setup() : 
    size(480,360,IG.GL)
    MyParticle(IVec(0,0,0), IVec(10,0,0))

class MyParticle(IParticleTrajectory) : 
    def __init__(self, p, v) : 
        IParticleTrajectory.__init__(self,p,v) # initialize with position and velocity


     Random Walk Rule in Update Method

As a first step to add a behavior to a particle-based agent, we add a random walk behavior. Because this behavior is about updating an agent's own state, the behavior is described in update method. It has a rule to push itself with a random vector as a force in a random probability.

add_library('igeo')

def setup() : 
    size(480,360,IG.GL)
    MyParticle(IVec(0,0,0), IVec(10,0,0))

class MyParticle(IParticleTrajectory) : 
    def __init__(self, p, v) : 
        IParticleTrajectory.__init__(self,p,v) # initialize with position and velocity
        self.fric(0.05) # 5% friction
    
    def update(self) : 
        if IRand.pct(10) : 
            self.push(IRand.pt(-1000,-1000,0,1000,1000,0))


     Attraction Force Rule in Interact Method

As a second rule, the agent gets a rule to attract each other. Because this behavior is about interaction between agents of the same class, the rule is written inside interact method. An agent checks other agents if they are within a certain distance. If so it pushes others towards itself by calculating a difference vector. When attraction force is applied, the random walk force is still applied because all forces are added up as a vector.

add_library('igeo')

def setup() : 
    size(480,360,IG.GL)
    for i in range(50) : 
        MyParticle(IRand.pt(-50,-50,0,50,50,0), IVec(0,0,0))

class MyParticle(IParticleTrajectory) : 
    def __init__(self, p, v) : 
        IParticleTrajectory.__init__(self,p,v) # initialize with position and velocity
        self.fric(0.05) # 5% friction
    
    def interact(self, agents) : 
        for agent in agents : 
            if isinstance(agent, MyParticle) : 
                if agent is not self : 
                    if agent.pos().dist(self.pos()) < 15 :  # closer than 15
                        dif = self.pos().dif(agent.pos()) #other to this
                        dif.len(40) # intensity of force
                        agent.push(dif)
    
    def update(self) : 
        if IRand.pct(10) : 
            self.push(IRand.pt(-500,-500,0,500,500,0))


     Adding A State Property

The code below shows an example to add a property to a particle-based agent. In the example, the agent introduces a state property named state as an integer value. This integer value is used to switch the behavior in interact method either to attract, repel or do nothing (random walk is still applied in either case). Then the value of state is changed in a random probability in update method.

add_library('igeo')

def setup() : 
    size(480,360,IG.GL)
    for i in range(100) : 
        MyParticle(IRand.pt(-50,-50,0,50,50,0), IVec(0,0,0))

class MyParticle(IParticleTrajectory) : 
    def __init__(self, p, v) : 
        IParticleTrajectory.__init__(self,p,v) # initialize with position and velocity
        self.fric(0.05) # 5% friction
        self.state = 0 # initial state
    
    def interact(self, agents) : 
        for agent in agents : 
            if isinstance(agent, MyParticle) : 
                if agent is not self : 
                    if agent.pos().dist(self.pos()) < 15 : # closer than 15
                        dif = self.pos().dif(agent.pos())#other to this
                        dif.len(40) # intensity of force
                        if self.state == 1 : # attraction
                            agent.push(dif)
                        elif self.state == 2 : # repulsion
                            agent.pull(dif)
    
    def update(self) : 
        if IRand.pct(10) : 
            self.push(IRand.pt(-500,-500,0,500,500,0))

        if IRand.pct(1) : # switch state
            if self.state == 0 : # state 0 -> 1
                self.state = 1 # attraction
                self.clr(1.0,0,1.0)
            elif self.state == 1 : # state 1 -> 2
                self.state = 2 # repulsion
                self.clr(0,0,1.0)
            else : # state 2 -> 0
                self.state = 0 # random walk only
                self.clr(0.5)


     Other Agent Classes to Interact

The following code shows an example to bring another agent class to have interaction between different classes. An agent of class Anchor below is instantiated by MyParticle agent in a certain time interval (every 20 time frame) in update method. Then if it finds other Anchor agents created in the past within a certain distance (10), it draws a line between them. An Anchor agent also has a rule to delete itself after a a certain time frame (100).

add_library('igeo')

def setup() : 
    size(480,360,IG.GL)
    for i in range(100) : 
        MyParticle(IRand.pt(-50,-50,0,50,50,0), IVec(0,0,0))
    IG.bg(0)

class MyParticle(IParticle) : 
    def __init__(self, p, v) : 
        IParticle.__init__(self,p,v) # initialize with position and velocity
        self.fric(0.05) # 5% friction
        self.state = 0 # initial state
    
    def interact(self, agents) : 
        for agent in agents : 
            if isinstance(agent, MyParticle) : 
                if agent is not self : 
                    if agent.pos().dist(self.pos()) < 15 : # closer than 15
                        dif = self.pos().dif(agent.pos())#other to this
                        dif.len(20) # intensity of force
                        if self.state == 1 : # attraction
                            agent.push(dif)
                        elif self.state == 2 : # repulsion
                            agent.pull(dif)
    
    def update(self) : 
        if IRand.pct(10) : 
            self.push(IRand.pt(-500,-500,0,500,500,0))

        if IRand.pct(1) : # switch state
            if self.state == 0 : # state 0 -> 1
                self.state = 1 # attraction
                self.clr(1.0,0,1.0)
            elif self.state == 1 : # state 1 -> 2
                self.state = 2 # repulsion
                self.clr(0,0,1.0)
            else : # state 2 -> 0
                self.state = 0 # random walk only
                self.clr(0.5)
            
        if self.time()%20 == 0 : 
            Anchor(self.pos().cp())


class Anchor(IAgent) :
    def __init__(self, p) : 
        self.pos = p
        self.point = IPoint(self.pos).clr(1.0,0,0).size(2)
    
    def interact(self, agents) : 
        if self.time() == 0 :  # only when the first time
            for agent in agents : 
                if isinstance(agent, Anchor) : 
                    if agent is not self and agent.time() > 0 : # exclude anchors just created
                        if agent.pos.dist(self.pos) < 10 :  # closer than 10
                            ICurve(agent.pos, self.pos).clr(1.0,0.1)
    
    def update(self) : 
        if self.time()==100 : # delete after 100 time frame
            self.point.del()
            self.del()


(back to the list of tutorials)

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