Repository navigation
Expand file tree
/
Copy pathheadlessflock.html
More file actions
126 lines (106 loc) · 4.63 KB
/
Copy pathheadlessflock.html
File metadata and controls
126 lines (106 loc) · 4.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
<html>
<head>
<title>Headless Flock Model</title>
<script src="../lib/agentscript.js"></script>
<script src="../tools/coffee-script.js"></script>
<script type="text/coffeescript">
u = ABM.Util # ABM.Util alias
class MyModel extends ABM.Model
setVision: (@vision) -> @patches.cacheRect @vision, true
setMaxTurn: (@maxTurn) -> @maxTurn = u.degToRad(@maxTurn)
toggleConsole: () -> @useConsole = not @useConsole
setup: ->
# u.randomSeed() # use for repeatable runs
@refreshPatches = false # <3fps->4fps turtles larger part of drawing
# No optimizations: 4fps
# @patches.usePixels() # 4fps same as refresh off
@patches.cacheTurtlesHere() # 17fps, big help for inRadius
# w/ refresh off and two optimizations, 22-23fps
# @turtles.setUseSprites() # 24 -> 36
# Default is untimed, fastest for headless
@anim.setRate 5, false # multistep
@useConsole = true
@population = 300 # turtles
@setVision 3 # patches & set patch rect
@minSeparation = 0.75 # patches
@setMaxTurn(3.0) # degrees -> radians
# defaults
@turtles.setDefault "size", 1.5
# @turtles.setDefault "color", [255,0,0] # slightly faster! ->38/39 ??
p.color = u.randomGray 0, 100 for p in @patches
p.sprout 1 for p in @patches.nOf(@population)
a.color = u.randomMapColor() for a in @turtles
newDomEl = (turtle) =>
coords = @patches.patchXYtoPixelXY(turtle.x, turtle.y)
el = document.body.appendChild(document.createElement("div"))
el.innerHTML = 'bird'
el.style.position = 'absolute'
el.style.webkitTransform = 'translate('+coords[0]+'px, '+coords[1]+'px)'
el.style.MozTransform = 'translate('+coords[0]+'px, '+coords[1]+'px)'
return el
@domElements = (newDomEl(turtle) for turtle in @turtles)
step: ->
if @useConsole and @anim.ticks % 100 is 0
console.log "flock alignment: #{@reportFlockVectorSize()}"
@flock(a) for a in @turtles
@stop() if @anim.ticks is 400
@renderInDOM(a) for a in @turtles
renderInDOM: (turtle) ->
coords = @patches.patchXYtoPixelXY(turtle.x, turtle.y)
el = @domElements[turtle.id]
el.style.webkitTransform = 'translate('+coords[0]+'px, '+coords[1]+'px)'
el.style.MozTransform = 'translate('+coords[0]+'px, '+coords[1]+'px)'
flock: (a) -> # a is turtle
flockmates = @turtles.inRadius a, @vision
if flockmates.length isnt 0
[nearestNeighbor, d] = u.minOneOf flockmates, ((f) -> f.distance a), true
if d < @minSeparation
@separate a, nearestNeighbor
else
@align a, flockmates
@cohere a, flockmates
a.forward .5 # move partial patch for smooth animation.
separate: (a, nearest) ->
h = nearest.towards a; @turnTowards a, h
align: (a, flockmates) ->
@turnTowards a, @averageHeading(flockmates)
cohere: (a, flockmates) ->
@turnTowards a, @averageHeadingTowards(a, flockmates)
turnTowards: (a, heading) ->
turn = u.subtractRads heading, a.heading # angle from h to a
turn = u.clamp turn, -@maxTurn, @maxTurn # limit the turn
a.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: (a, flockmates) ->
dx = (Math.sin f.towards a for f in flockmates).reduce (x,y) -> x+y
dy = (Math.cos f.towards a for f in flockmates).reduce (x,y) -> x+y
@safeAtan dy, dx
safeAtan: (x,y) -> Math.atan2 y, x # if x is 0 and y is 0 then 0 else Math.atan2 y, x # atan ok if x 0
reportFlockVectorSize: ->
dx = (Math.sin a.heading for a in @turtles).reduce (x,y) -> x+y
dy = (Math.cos a.heading for a in @turtles).reduce (x,y) -> x+y
Math.sqrt(dx*dx + dy*dy)/@population
# div, patchSize, minX, maxX, minY, maxY, isTorus, hasNeighbors
# Defaults: 13, -16, 16, -16, 16, false, true, false
# No div, therefore no model drawings
model = new MyModel({
size: 15,
minX: -16,
maxX: 16,
minY: -16,
maxY: 16,
isTorus: true,
hasNeighbors: false
})
.debug() # Debug: Put Model vars in global name space
.start() # Run model immediately after startup initialization
</script>
</head>
<body>
<div id="layers"></div>
<div id="play" style="float:right;"></div>
</body>
</html>