-
Notifications
You must be signed in to change notification settings - Fork 5
/
Boids.gaml
229 lines (201 loc) · 7.16 KB
/
Boids.gaml
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
/**
* Name: Boids
* Author:
* Description: This model shows the movement of boids following a goal, and creating
* without their own volonty, a flock. The experiment proposes to display in a 3D view
* the different boids and allows the user to move the goal to see the behaviour of boids.
* Tags: gui, skill
*/
model boids
global torus: torus_environment{
//Number of boids that will be created
int number_of_agents <- 50 min: 1 max: 1000000;
//Number of obstacles for the boids movement to represent
int number_of_obstacles <- 0 min: 0;
//Maximal speed of the boids
float maximal_speed <- 15.0 min: 0.1 max: 15.0;
//Factors for the group of boids
int cohesion_factor <- 200;
int alignment_factor <- 100;
//Variables for the movement of the boids
float minimal_distance <- 10.0;
int width_and_height_of_environment <- 1000;
bool torus_environment <- false;
bool apply_cohesion <- true ;
bool apply_alignment <- true ;
bool apply_separation <- true;
bool apply_avoid <- true;
bool apply_wind <- true;
bool moving_obstacles <- false;
int bounds <- int(width_and_height_of_environment / 20);
//Vector for the wind
point wind_vector <- {0,0};
list images of: image_file <- [file('../images/bird1.png'),file('../images/bird2.png'),file('../images/bird3.png')];
int xmin <- bounds;
int ymin <- bounds;
int xmax <- (width_and_height_of_environment - bounds);
int ymax <- (width_and_height_of_environment - bounds);
//Action to move the goal to the mouse location
action move_goal {
ask first(boids_goal) {
do goto target: #user_location speed: 30.0;
}
}
geometry shape <- square(width_and_height_of_environment);
init {
//Create the boids agents
create boids number: number_of_agents {
location <- {rnd (width_and_height_of_environment - 2) + 1, rnd (width_and_height_of_environment -2) + 1 };
}
//Create the obstacles agents
create obstacle number: number_of_obstacles {
location <- {rnd (width_and_height_of_environment - 2) + 1, rnd (width_and_height_of_environment -2) + 1 };
}
//Create the goal that boids will follow
create boids_goal;
}
}
//Species boids goal which represents the goal that will be followed by boids agents using the skill moving
species boids_goal skills: [moving] {
float range <- 20.0;
//If the mouse is not used, then the goal just wander
reflex wander {
do wander amplitude: 45 speed: 20.0;
}
aspect default {
draw circle(10) color: #red ;
draw circle(40) color: #orange empty: true;
}
}
//Species boids which represents the boids agents whom follow the boid goal agents, using the skill moving
species boids skills: [moving] {
//Speed of the boids agents
float speed max: maximal_speed <- maximal_speed;
//Range used to consider the group of the agent
float range <- minimal_distance * 2;
point velocity <- {0,0};
//Reflex used when the separation is applied to change the velocity of the boid
reflex separation when: apply_separation {
point acc <- {0,0};
ask (boids overlapping (circle(minimal_distance))) {
acc <- acc - ((location) - myself.location);
}
velocity <- velocity + acc;
}
//Reflex to align the boid with the other boids in the range
reflex alignment when: apply_alignment {
list others <- ((boids overlapping (circle (range))) - self);
point acc <- mean (others collect (each.velocity)) - velocity;
velocity <- velocity + (acc / alignment_factor);
}
//Reflex to apply the cohesion of the boids group in the range of the agent
reflex cohesion when: apply_cohesion {
list others <- ((boids overlapping (circle (range))) - self);
point mass_center <- (length(others) > 0) ? mean (others collect (each.location)) : location;
point acc <- mass_center - location;
acc <- acc / cohesion_factor;
velocity <- velocity + acc;
}
//Reflex to avoid the obstacles
reflex avoid when: apply_avoid {
point acc <- {0,0};
list<obstacle> nearby_obstacles <- (obstacle overlapping (circle (range)) );
loop obs over: nearby_obstacles {
acc <- acc - ((location of obs) - my (location));
}
velocity <- velocity + acc;
}
//action to represent the bounding of the environment considering the velocity of the boid
action bounding {
if !(torus_environment) {
if (location.x) < xmin {
velocity <- velocity + {bounds,0};
} else if (location.x) > xmax {
velocity <- velocity - {bounds,0};
}
if (location.y) < ymin {
velocity <- velocity + {0,bounds};
} else if (location.y) > ymax {
velocity <- velocity - {0,bounds};
}
}
}
//Reflex to follow the goal
reflex follow_goal {
velocity <- velocity + ((first(boids_goal).location - location) / cohesion_factor);
}
//Reflex to apply the wind vector on the velocity
reflex wind when: apply_wind {
velocity <- velocity + wind_vector;
}
//Action to move the agent
action do_move {
if (((velocity.x) as int) = 0) and (((velocity.y) as int) = 0) {
velocity <- {(rnd(4)) -2, (rnd(4)) - 2};
}
point old_location <- copy(location);
do goto target: location + velocity;
velocity <- location - old_location;
}
//Reflex to apply the movement by calling the do_move action
reflex movement {
do do_move;
}
aspect image {
draw (images at (rnd(2))) size: {50,50} rotate: heading ;
}
aspect circle {
draw circle(15) color: #red;
}
aspect default {
draw circle(20) color: #lightblue empty: true;
}
}
//Species obstacle that represents the obstacles avoided by the boids agents using the skill moving
species obstacle skills: [moving] {
float speed <- 2.0;
geometry shape <- triangle(15);
//Reflex to move the obstacles if it is available
reflex move_obstacles when: moving_obstacles {
//Will make the agent go to a boid with a 50% probability
if flip(0.5)
{
do goto target: one_of(boids);
}
else{
do wander amplitude: 360;
}
}
aspect default {
draw triangle(20) color: #black ;
}
}
experiment boids_gui type: gui {
parameter 'Number of agents' var: number_of_agents;
parameter 'Number of obstacles' var: number_of_obstacles;
parameter 'Maximal speed' var: maximal_speed;
parameter 'Cohesion Factor' var: cohesion_factor;
parameter 'Alignment Factor' var: alignment_factor;
parameter 'Minimal Distance' var: minimal_distance;
parameter 'Width/Height of the Environment' var: width_and_height_of_environment ;
parameter 'Toroidal Environment ?' var: torus_environment ;
parameter 'Apply Cohesion ?' var: apply_cohesion ;
parameter 'Apply Alignment ?' var: apply_alignment ;
parameter 'Apply Separation ?' var: apply_separation ;
parameter 'Apply Avoidance ?' var: apply_avoid ;
parameter 'Apply Wind ?' var: apply_wind ;
parameter 'Moving Obstacles ?' var: moving_obstacles ;
parameter 'Direction of the wind' var: wind_vector ;
//Minimum duration of a step to better see the movements
float minimum_cycle_duration <- 0.01;
output {
display Sky background: #blue type: opengl {
image '../images/sky.jpg' refresh: false;
species boids aspect: image trace: 10 fading: true ;
species boids_goal;
species obstacle;
//Event to call the action move_goal in global if the mouse move within the experiment
event mouse_move action: move_goal;
}
}
}