Repository navigation
Expand file tree
/
Copy pathflockui.html
More file actions
156 lines (138 loc) · 4.97 KB
/
Copy pathflockui.html
File metadata and controls
156 lines (138 loc) · 4.97 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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
<html>
<head>
<title>Flock GUI Model</title>
<script src="../lib/agentscript.js"></script>
<script src="../tools/dat.gui.min.js"></script>
<script src="../lib/as.dat.gui.js"></script>
<script src="../tools/coffee-script.js"></script>
<script type="text/coffeescript">
u = ABM.Util # Aliases
Shapes = ABM.Shapes
class MyModel extends ABM.Model
setVision: (@vision) -> @patches.cacheRect @vision, true
setMaxTurn: (maxTurn) -> @maxTurn = u.degToRad(maxTurn)
toggleConsole: () -> @useConsole = not @useConsole
resetPopulation: (@population) ->
change = @population - @turtles.length
if change > 0
p.sprout 1 for p in @patches.nOf(change)
else
t.die() for t in @turtles.nOf(-change)
change # CS always returns something, this made some sense
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
# Deprecated:
# @turtles.setUseSprites() # 24 -> 36
@turtles.setDefault "useSprites", true
# @anim.setRate 30, true # multistep
@useConsole = true
@population = 150 # turtles (was more, Chrome regression problem)
@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
step: ->
if @useConsole and @anim.ticks % 25 is 0
# console.log @anim.toString(), "flock alignment: #{@reportFlockVectorSize()}"
console.log "flock alignment: #{@reportFlockVectorSize()}"
@flock(a) for a in @turtles
flock: (a) -> # a is turtle
flockmates = @turtles.inRadius(a, @vision).other(a)
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
model = new MyModel({
div: "layers",
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
gui = new ABM.DatGUI(model, {
"turning radius (deg)": {
type: "slider",
min: 0,
max: 10,
step: 0.5,
val: 3,
smooth: true,
setter: "setMaxTurn"
},
"minSeparation": {
type: "slider",
min: 0,
max: 10,
step: 0.25,
val: 0.75,
smooth: true
},
"vision radius": {
type: "slider",
min: 0,
max: 15,
step: 1,
val: 3,
smooth: true,
setter: "setVision"
},
"population": {
type: "slider",
min: 50,
max: 500,
step: 25,
val: 150,
smooth: true,
setter: "resetPopulation"
}
})
</script>
</head>
<body>
<div id="layers"></div>
</body>
</html>