11# The Flock (a list of Boid objects)
22require 'forwardable'
33
4- class Flock
4+ # The flock class is enumerable
5+ class Flock
56 extend Forwardable
6- def_delegators ( :@boids , :each , :<< , :reject )
7+ def_delegators ( :@boids , :each , :reject , :<< )
78 include Enumerable
8-
9+
910 def initialize ( size , position )
10- @boids = ( 0 ..size ) . map { Boid . new ( position ) }
11+ @boids = ( 0 ..size ) . map { Boid . new ( position ) }
1112 end
1213
1314 def run
1415 self . each do |bird |
1516 bird . run ( self ) # Passing the entire list of boids to each boid individually
1617 end
17- end
18+ end
1819end
1920
2021# The Boid class
2122
2223class Boid
2324 include Processing ::Proxy
24- attr_reader :location , :velocity , :acceleration , :r , :maxforce , :maxspeed
25- attr_reader :width , :height
25+ attr_reader :location , :velocity , :acceleration , :rad , :maxforce , :maxspeed
2626 def initialize ( loc )
2727 @acceleration = Vec2D . new
2828 @velocity = Vec2D . random
2929 @location = loc
30- @r = 2.0
30+ @rad = 2.0
3131 @maxspeed = 2
3232 @maxforce = 0.03
33- @width = Processing . app . width
34- @height = Processing . app . height
3533 end
36-
34+
3735 def run ( boids )
3836 flock ( boids )
3937 update
4038 borders
4139 render
4240 end
43-
41+
4442 def apply_force ( force )
4543 # We could add mass here if we want A = F / M
4644 @acceleration += force
4745 end
48-
49- # We accumulate a new acceleration each time based on three rules
46+
5047 def flock ( boids )
51- sep = separate ( boids ) # Separation
52- ali = align ( boids ) # Alignment
53- coh = cohesion ( boids ) # Cohesion
54- # Arbitrarily weight these forces
55- sep *= 1.5
56- ali *= 1.0
57- coh *= 1.0
58- # Add the force vectors to acceleration
59- apply_force ( sep )
60- apply_force ( ali )
61- apply_force ( coh )
48+ calculate_forces ( boids ) . each { |force | apply_force ( force ) }
49+ end
50+
51+ # We calculate the forces each time based on three rules
52+ def calculate_forces ( boids )
53+ forces = [ ]
54+ forces << separate ( boids ) * 1.5 # Separation weighted 1.5
55+ forces << align ( boids ) # Alignment weighted 1.0
56+ forces << cohesion ( boids ) # Cohesion weighted 1.0
6257 end
63-
58+
59+
6460 # Method to update location
6561 def update
6662 # Update velocity
@@ -71,7 +67,7 @@ def update
7167 # Reset accelertion to 0 each cycle
7268 @acceleration *= 0
7369 end
74-
70+
7571 # A method that calculates and applies a steering force towards a target
7672 # STEER = DESIRED MINUS VELOCITY
7773 def seek ( target )
@@ -82,7 +78,7 @@ def seek(target)
8278 # Steering = Desired minus Velocity
8379 steer = desired - velocity
8480 # Limit to maximum steering force
85- steer . set_mag ( maxforce ) { steer . mag > maxforce }
81+ steer . set_mag ( maxforce ) { steer . mag > maxforce }
8682 return steer
8783 end
8884
@@ -95,21 +91,21 @@ def render
9591 translate ( location . x , location . y )
9692 rotate ( theta )
9793 begin_shape ( TRIANGLES )
98- vertex ( 0 , -r * 2 )
99- vertex ( -r , r * 2 )
100- vertex ( r , r * 2 )
94+ vertex ( 0 , -rad * 2 )
95+ vertex ( -rad , rad * 2 )
96+ vertex ( rad , rad * 2 )
10197 end_shape
10298 pop_matrix
10399 end
104100
105101 # Wraparound
106102 def borders
107- location . x = width + r if location . x < -r
108- location . y = height + r if location . y < -r
109- location . x = -r if location . x > width + r
110- location . y = -r if location . y > height + r
103+ location . x = width + rad if location . x < -rad
104+ location . y = height + rad if location . y < -rad
105+ location . x = -rad if location . x > width + rad
106+ location . y = -rad if location . y > height + rad
111107 end
112-
108+
113109 # Separation
114110 # Method checks for nearby boids and steers away
115111 def separate ( boids )
@@ -119,7 +115,7 @@ def separate(boids)
119115 # For every other bird in the system, check if it's too close
120116 boids . reject { |bd | bd . equal? self } . each do |other |
121117 d = location . dist ( other . location )
122- # If the distance is greater than 0 and less than an arbitrary amount
118+ # If the distance is greater than 0 and less than an arbitrary amount
123119 if ( 0.0001 ..desiredseparation ) . include? d
124120 # Calculate vector pointing away from neighbor
125121 diff = location - other . location
@@ -133,18 +129,18 @@ def separate(boids)
133129 if count > 0
134130 steer /= count . to_f
135131 end
136-
132+
137133 # As long as the vector is greater than 0
138134 if steer . mag > 0
139135 # Implement Reynolds: Steering = Desired - Velocity
140136 steer . normalize!
141137 steer *= maxspeed
142- steer -= velocity
143- steer . set_mag ( maxforce ) { steer . mag > maxforce }
138+ steer -= velocity
139+ steer . set_mag ( maxforce ) { steer . mag > maxforce }
144140 end
145141 return steer
146142 end
147-
143+
148144 # Alignment
149145 # For every other nearby boid in the system, calculate the average velocity
150146 def align ( boids )
@@ -168,7 +164,7 @@ def align(boids)
168164 end
169165 return steer
170166 end
171-
167+
172168 # Cohesion
173169 # For the average location (i.e. center) of all other nearby boids, calculate
174170 # steering vector towards that location
@@ -184,6 +180,6 @@ def cohesion(boids)
184180 end
185181 end
186182 sum /= count unless count == 0 # avoid div by zero
187- ( count > 0 ) ? seek ( sum ) : Vec2D . new
183+ ( count > 0 ) ? seek ( sum ) : Vec2D . new
188184 end
189185end
0 commit comments