flocking


Information

Created with NetLogo version NetLogo 3.0
Running with NetLogoLite.jar version 302.



Procedures

NetLogo Version: NetLogo 3.0

;; SUMMARY
;;;;  A NetLogo model.
;; COPYRIGHT & LICENSE
;;;; Copyright  2004,2005 James P. Steiner
;;;; Some Rights Reserved.
;;;; Creative Commons Attribution-NonCommercial-ShareAlike License v. 2.0.
;;;; Visit http://creativecommons.org/licenses/by-nc-sa/2.0/ for more information.
;;
breeds [ ducks]

ducks-own [ new-heading flockmates my-speed ]

to startup
   setup
end   

to setup
  ca
  create-custom-ducks population
    [ make-duck
    ]
end

to scatter ;; ducks
      setxy (random-int-or-float screen-size-x) - screen-edge-x (random-int-or-float screen-size-y) - screen-edge-y
      set heading random-int-or-float 360.0
      set new-heading heading
end

to go
  ;; the model runs faster if we don't update the screen
  ;; until after all turtles have moved
  ; no-display 
  check-pop
  ask ducks [ flock ]
  ask ducks [ move  ]
  ; display
end

to check-pop
   locals [ curr-pop ]
   set curr-pop ( count ducks )
   if curr-pop != population
   [ ifelse population > curr-pop 
     [ ;; make new ducks
       create-custom-ducks (population - curr-pop)
       [ make-duck
       ]
     ]
     [ ;; kill extra ducks 
       repeat (curr-pop - population)
       [ ask random-one-of ducks [ die ]
       ]
     ]
  ]
end

to make-duck
    set color yellow - 2 + random-int-or-float 7  ;; random shades look nice
    scatter
    set my-speed speed ; + speed * (( random 1.0) - .5)
end

to flock  ;; turtle procedure
  locals [ closest-duck
           cohere-heading
           conform-heading
           avoid-heading
           spleen-heading
           close-duck-distance
           panic
         ]
  
  set new-heading heading
  set cohere-heading heading
  set conform-heading heading
  set avoid-heading heading
  set spleen-heading heading + wheel  
  
  set flockmates visible-ducks
  
  if any? flockmates
  [
    set closest-duck duck-closest-to-me
    ;; avoid

    set close-duck-distance (distance closest-duck)
    if close-duck-distance < comfort-zone 
    [ ifelse close-duck-distance > 0
      [ set avoid-heading ( normal-360 ( 180 + towards closest-duck ) )
        set avoid-heading weighted-mean heading avoid-heading
            ( ( comfort-zone ) - close-duck-distance ) / ( comfort-zone * .5 )
      ]
      [ set avoid-heading random 360
      ]
   ]
      
    ;; cohere
    if mean-flockmates-distance > comfort-zone
    [ set cohere-heading  towards-flockmates-center ]

    ;; conform
    set conform-heading  mean-flockmates-heading
    
    set new-heading weighted-mean-multi
     spleen-heading independence
     avoid-heading  caution
     cohere-heading cohesion
     conform-heading conformity
  ]
    
end

to move
  set heading new-heading
  jump speed; my-speed
end

;;; HELPER PROCEDURES

to-report visible-ducks
  locals [ nearby-ducks]
  set nearby-ducks ducks in-radius vision-range with [self != myself]
  ifelse any? nearby-ducks
  [ report nearby-ducks with 
    [ ( vision-angle - field-of-view) < abs( subtract-headings ( heading-of myself ) ( normal-360 ( away-from myself ) ) )
        and
      ( vision-angle + field-of-view) > abs( subtract-headings ( heading-of myself ) ( normal-360 ( away-from myself ) ) )
    ]
  ]
  [ report nearby-ducks ]
  
end       

to-report duck-closest-to-me ;; turtle procedure
  report min-one-of flockmates [distance myself ]
end

to-report mean-flockmates-heading  ;; turtle procedure
  ;; We can't just average the heading variables here.
  ;; For example, the average of 1 and 359 should be 0,
  ;; not 180.  So we have to use trigonometry.
  let mean-sin mean values-from flockmates [sin heading]
  let mean-cos mean values-from flockmates [cos heading]
  ifelse mean-sin != 0 or mean-cos != 0
  [ report atan mean-sin mean-cos ]
  [ report 0 ]
end

to-report weighted-mean-multi [ ah aw bh bw ch cw dh dw ]
  ifelse (aw + bw + cw + dw) = 0
  [ report ah ]
  [ report atan ( (   (sin ah ) * aw
                    + (sin bh ) * bw 
                    + (sin ch ) * cw
                    + (sin dh ) * dw
                   ;+ (sin eh ) * ew 
                 ) / (aw + bw + cw + dw )
               )
               ( (   (cos ah ) * aw
                   + (cos bh ) * bw 
                   + (cos ch ) * cw
                   + (cos dh ) * dw
                  ;+ (cos eh ) * ew 
                 ) / (aw + bw + cw + dw )
               )
  ]
end

to-report weighted-mean [ a b c ]
    report normal-360 atan ( ( sin a + sin b ) * (  c  ) )
                           ( ( cos a + cos b ) * (1 - c) )
end
                                                
to-report towards-flockmates-center ;; turtle procedure
  ;; "towards myself" gives us the heading from the other turtle
  ;; to me, but we want the heading from me to the other turtle,
  ;; so we add 180
  report normal-360 ( atan mean values-from flockmates [sin (normal-360 (smart-towards-myself + 180 ))]
                           mean values-from flockmates [cos (normal-360 (smart-towards-myself + 180 ))] )
end

to-report mean-flockmates-distance
    report mean values-from flockmates [ distance myself ]
end

to-report smart-towards-myself
   ifelse xcor != xcor-of myself or ycor != ycor-of myself
   [ report towards myself ]
   [ report random-float 360 ]
end   
;;; PATTERN

;to pattern ;; option 1: veer to create preferred angle re nearest neighbor
;  set vee-angle subtract-headings (towards closest-duck) heading
;  set heading heading + sin( 90 + vee-angle - flock-angle )
;end      

;; ACCELLERATE      
;to accelerate
;  if speed < 1 [ set speed speed + .1 ]
;  if speed > 1 [ set speed speed - .1 ]
;end

to-report plus-or-minus-one
    report 2 * ( 0.5 - random-int-or-float 2 )
end

To-report normal-360 [ input-angle ]
; normalizes the input angle to be between 0 and 359.9999 ( 0.0 <= angle < 360.0 )
    locals [ angle ]    
      set angle input-angle
    while [ angle < 0.0 ]
      [ set angle angle + 360.0 ]
    while [ angle >= 360.0 ]
      [ set angle angle - 360.0 ]
    report angle
end

to-report away-from [ agent ]
   ifelse xcor-of agent != xcor or ycor-of agent != ycor
   [ report 180 + towards agent ]
   [ report 0 ]
end   

;; To find the difference between two headings, we can't just
;; subtract the numbers, because 0 and 360 are the same heading.
;; For example, the difference between a heading of 5 degrees
;; and a heading of 355 degrees is 10 degrees, not 350 degrees.
;;;;to-report subtract-headings [h1 h2]
;;;;  ifelse abs (h1 - h2) <= 180
;;;;    [ report h1 - h2 ]
;;;;    [ ifelse h1 > h2
;;;;        [ report h1 - h2 - 360 ]
;;;;        [ report h1 - h2 + 360 ] ]
;;;;end

                    


Download Link

View or download the complete model file (to download: right-click, save-link-as):
-- Download flocking --