Complex Boundaries

Hi @LordCacops,

I think @monkstone 's suggestion is well suited for what you’re trying to achieve.
Here’s a simple example sketch in Python mode based on the (very useful) examples he provided in this thread and on his gist.

(Click the mouse to change mode: enclosing/avoidance)

add_library('geomerative')

# Polygon parameters
N = 10
angle = radians(360) / N
radius = 200

# Enclose Mode (enclosing or repulsing particles)
Enclose = True

def setup():
    size(1000, 600, P2D)
    smooth(8)
    
    global polyshape, balls, center

    # Array of Ball() objects
    balls = [Ball() for i in xrange(30)]
    
    # Instantiating our RPolygon
    RG.init(this)
    rpoly = RPolygon()
    
    # Building polygon from vertices location
    for i in xrange(N):
        r = random(.5, 1.3)
        x = cos(angle * i) * (radius * r)  + width/2
        y = sin(angle * i) * (radius * r)  + height/2
        rpoly.addPoint(RPoint(x, y))
     
    # Converting our RPolygon() to RShape()  
    polyshape = RShape(rpoly.toShape())
    
    # Stores location of its centroid
    center = polyshape.getCentroid()
    
    
def draw():
    pushStyle()
    noStroke()
    fill(255, 100)
    rect(0, 0, width, height)
    popStyle()
    
    # Displaying balls + updating location
    for b in balls:
        b.update()
        b.render()
    
    # Drawing our polygon shape
    pushStyle()
    stroke('#504AFF')
    strokeWeight(2)
    noFill()
    polyshape.draw()
    popStyle()
    

       
class Ball(object):
    def __init__(self):
        self.loc = PVector(random(width), random(height))
        self.vel = PVector.random2D()
        
    def update(self):
        self.loc.add(self.vel) # Updating location
        self.vel.limit(2) # Limiting velocity
        
        dir = PVector(center.x, center.y).sub(self.loc) # Direction
        f = dir.sub(self.vel).normalize().mult(.1) # Force (remove 'mult()' for a hard stop)
        
        if Enclose:
            # If ball not within the boundaries of the polygon:
            # --> divert it back to the center of the poygon
            if not polyshape.contains(RPoint(self.loc.x, self.loc.y)):
                self.vel.add(f)
        
        # Else --> avoidance behavior
        elif polyshape.contains(RPoint(self.loc.x, self.loc.y)):
            self.vel.sub(f)
                
        # Canvas boundaries       
        if self.loc.x > width or self.loc.x < 0: self.vel.x *= -1
        if self.loc.y > height or self.loc.y < 0: self.vel.y *= -1


    def render(self):
        if polyshape.contains(RPoint(self.loc.x, self.loc.y)):
            strokeWeight(10)
            stroke('#FF4A62')
        else:
            strokeWeight(6)
            stroke('#69C375')
            
        point(self.loc.x, self.loc.y, self.loc.z)
        
def mouseClicked():
    global Enclose
    Enclose = not Enclose
    print "Enclose Mode is %s" % Enclose
1 Like