Bill Manaris : Fall 2006 / Sample Program

# flock1.py    Version 1.0   9-oct-06    (bzm)
#
# Simulates 3D boid behavior in VPython.
#
# The following general algorithm is followed:
# (see http://www.visualbots.com/flock_project.htm)
#
#For each Time Step Do the Following....
#    For Each Bot In Bots ("sensing" loop)
#        Calculate steering behaviors
#        Calculate composite behavior
#        Store composite behavior into Bot memory
#    For Each Bot In Bots ("action" loop)
#        Turn according to the stored composite behavior
#        Move to next position
#
# For steering behavior possibilities see:
# http://www.vergenet.net/~conrad/boids/pseudocode.html
#

"Simulates 3D flocking behavior of boids in VPython."

from math import *
from boid import *

dt = 1.0     # time interval between animation frames

# boid constants
boidColor = color.blue      # color of boids
boidRadius = 0.2            # radius of boids
boidDiameter = boidRadius*2

# boid behavior constants
minSeparation = boidDiameter              # closest allowable distance between boids
flockThershold = boidDiameter * 500       # boids closer than this are in a local flock
cohesionFactor = 1.0/200                  # larger for quicker cohesion
alignmentFactor = 1.0/2                   # larger for quicker alignment

def main():
    "Performs boid simulation."

    boids = []    # list of boids
    numBoids = input("Enter number of boids: ")

    #boids = randomBoids(boids, numBoids, boidRadius, boidColor)
    boids = placeBoidsViaMouse(boids, numBoids, boidRadius, boidColor)

    # if you want obstacles, append them to boids
    # (but you have to treat them differently when rules are considered)

    # convert to array for faster indexing access
    boids = array(boids)

    # animate boids (press 'Escape' to end)
    while (True):

        # sensing and action loop   
        for boid in boids:

            # calculate steering behaviors

            # Rule 1 - Cohesion: Boids try to fly towards the centre of mass of neighbouring boids
            v1 = boidCohesion(boid, boids)

            # Rule 2 - Separation: Boids try to keep a small distance away from other objects (including other boids)
            v2 = boidSeparation(boid, boids)

            # Rule 3 - Alignment: Boids try to match velocity with near boids
            v3 = boidAlignment(boid, boids)

            # create composite behavior
            boid.setVelocity(boid.getVelocity() + v1 + v2 + v3)

        # action loop
        for boid in boids:
            boid.move(dt)   # adjust boid position

        # check mouse events and update boids as specified
        moveBoidViaMouse(boids)


def boidCohesion(boid, boids):
    "Return new velocity aiming towards center of flock."

    flockCenter = vector(0,0,0)  # initialize

    # calculate cumulative position of flock mates
    for flockmate in boids:
        if flockmate != boid:
            flockCenter = flockCenter + flockmate.getPos()

    # get center of mass of all other boids
    flockCenter = flockCenter / (len(boids)-1)
    velocity = (flockCenter - boid.getPos()) * cohesionFactor

    return velocity


def boidSeparation(boid, boids):
    "Return new velocity vector to best avoid crowding flockmates."

    velocity = vector(0,0,0)
    # calculate velocity vector to best avoid crowding flockmates
    for flockmate in boids:
        separation = boid.distance(flockmate)
        # are we too close for comfort?
        if flockmate != boid and separation < minSeparation:
            velocity = velocity - (flockmate.getPos() - boid.getPos())

    return velocity


def boidAlignment(boid, boids):
    "Return new velocity to match boid's velocity with local flockmates."

    flockVelocity = vector(0,0,0)   # initialize
    flockMateCount = 0              # number of local flock mates
    # calculate cumulative velocity of local flock mates
    for flockmate in boids:
        separation = boid.distance(flockmate)
        # select only local flockmates
        if flockmate != boid and separation < flockThershold:
            flockMateCount += 1   # found one more flock mate
            flockVelocity = flockVelocity + flockmate.getVelocity()

    # calculate velocity aiming towards average position of flockmates (if any)
    if flockMateCount > 0:
        flockVelocity = flockVelocity / flockMateCount
        velocity = (flockVelocity - boid.getVelocity()) * alignmentFactor
    else:
        velocity = vector(0,0,0)   # no local flock mates to aim towards

    return velocity

#-----

if __name__ == '__main__':
    main()


 
(Printable View of http://www.cs.cofc.edu/~manaris/?n=Fall2006.SampleProgram)