Skip to content

Instantly share code, notes, and snippets.

@wybo
Last active May 1, 2017 23:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wybo/82ef4f46d2a05838dc5f to your computer and use it in GitHub Desktop.
Save wybo/82ef4f46d2a05838dc5f to your computer and use it in GitHub Desktop.
Flock
# AgentBase is Free Software, available under GPL v3 or any later version.
# Original AgentScript code @ 2013, 2014 Owen Densmore and RedfishGroup LLC.
# AgentBase (c) 2014, Wybo Wiersma.
# Flock is the classic "boids" model where agents each follow
# three simple rules resulting in realistic flocking. This example
# uses the as.dat.gui.js extra.
u = ABM.util
class ABM.FlockModel extends ABM.Model
setVision: (@vision) ->
setMaxTurn: (@maxTurn) ->
@maxTurn = u.degreesToRadians(@maxTurn)
toggleConsole: () ->
@useConsole = not @useConsole
setup: ->
# u.randomSeed() # use for repeatable runs
@refreshPatches = false # <3fps->4fps agents larger part of drawing
# No optimizations: 4fps
# @patches.usePixels() # 4fps same as refresh off
# w/ refresh off and two optimizations, 22-23fps
@agents.setUseSprites() # 24 -> 36
@animator.setRate 30, true # multistep
@useConsole = true
@population = 75 # agents
@setVision 3 # patches & set patch rect
@minSeparation = 0.75 # patches
@setMaxTurn(3.0) # degrees -> radians
# defaults
@agents.setDefault "size", 1.5
@patches.create()
for patch in @patches
patch.color = u.color.random type: "gray", min: 0, max: 100
for patch in @patches.sample(@population)
patch.sprout 1
for agent in @agents
agent.color = u.color.random "map"
step: ->
if @useConsole and @animator.ticks % 25 is 0
console.log @animator.toString(),
"flock alignment: #{@reportFlockVectorSize()}"
for agent in @agents
@flock agent
flock: (agent) ->
flockmates = agent.neighbors(@vision)
if flockmates.length isnt 0
[nearestNeighbor, distance] = flockmates.min(((f) ->
f.distance agent.position), true)
if distance < @minSeparation
@separate agent, nearestNeighbor
else
@align agent, flockmates
@cohere agent, flockmates
agent.forward .5 # move partial patch for smooth animation.
separate: (agent, nearest) ->
angle = u.angle nearest.position, agent.position, @patches
@turnTowards agent, angle
align: (agent, flockmates) ->
@turnTowards agent, @averageHeading(flockmates)
cohere: (agent, flockmates) ->
@turnTowards agent, @averageHeadingTowards(agent, flockmates)
turnTowards: (agent, heading) ->
turn = u.substractRadians heading, agent.heading # angle from h to a
turn = u.clamp turn, -@maxTurn, @maxTurn # limit the turn
agent.rotate turn
averageHeading: (flockmates) ->
dx = (Math.sin f.heading for f in flockmates).reduce (x, y) -> x + y
dy = (Math.cos f.heading for f in flockmates).reduce (x, y) -> x + y
@safeAtan dy, dx
averageHeadingTowards: (agent, flockmates) ->
dx = (Math.sin u.angle(f.position, agent.position,
@patches) for f in flockmates).reduce (x, y) -> x + y
dy = (Math.cos u.angle(f.position, agent.position,
@patches) for f in flockmates).reduce (x, y) -> x + y
@safeAtan dy, dx
safeAtan: (x, y) ->
# if x is 0 and y is 0 then 0 else Math.atan2 y, x # atan ok if x 0
Math.atan2 y, x
reportFlockVectorSize: ->
dx = (Math.sin a.heading for a in @agents).reduce (x, y) -> x + y
dy = (Math.cos a.heading for a in @agents).reduce (x, y) -> x + y
Math.sqrt(dx * dx + dy * dy) / @population
window.model = new ABM.FlockModel({
div: "world",
patchSize: 15,
isTorus: true
})
window.model.start()
# Uses the AgentBase library (03-02-2017 release)
# https://github.com/wybo/agentbase/commit/3501302567c018da82601cd858be2ea6d0b9c74d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment