概要
Boids 2.2では、分離(Separation)に加えて「結合(Cohesion)」のルールを導入する。結合行動の考え方は、ここでは以下の通りとした。
- 前方視角内に個体が存在する場合、それらの重心位置を求める
- 進行方向を、重心の方へ向けて少し変更する
結合のアルゴリズム
重心の算出
次図において、進行方向に直角な直線hより前方側の個体が存在する場合、それらの重心位置gを計算する。
      
なお、視野角の前方判定はベクトルの前後判定によって行っている。

進路変更
先の図のように、自身の進行方向に対する群の重心の位置によって、以下の手順で進路を変更する。
- 重心位置が自身の進行方向に対して左右どちら側にあるかを判定
- 重心位置がが進行方向より右側にあるなら右へ、左側にあるなら左へ方向を少し変化させる。
これらの考え方はBoids 2.1の分離行動における回避動作と同じ。
コード内容
初期パラメータ定義
HTMLで定義する初期パラメータに、結合に関する以下の変数を追加する。
- 結合の進行方向の変化(BD22_COHESION_ANGLE)
| 1 2 3 4 5 6 7 8 9 10 11 12 13 |   <script>   //<![CDATA[   BD22_V_MAX = 100;   BD22_CREATURE_SIZE = 10;   BD22_WALL_DETECTION_LENGTH = 100;   BD22_WALL_REPULSION_PARAM = 16;   BD22_VIEW_FIELD_LENGTH = 50;   BD22_SEPARATION_ANGLE = 10 * Math.PI / 180;   // Boids 2.2で追加:結合行動の速度の向きを変更する角   BD22_COHESION_ANGLE = 5 * Math.PI / 180;   BD22_INTERVAL_SEC = 0.05;   //]]>   </script> | 
クラス変数
初期パラメータの保存のため、Creatureクラスのクラス変数を追加する。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |   class Creature extends MovingAgent     # private staticなクラス・プロパティ     # 最大速度     @_vMax: 100     # 描画の基本となるサイズ     @_drawSize: 8     # 壁の衝突回避を認識する距離     @_wallDetectionLength:  100     # 反発力パラメータ     @_wallRepulsionParam: 4     # 視野の長さ(奥行)     @_viewFieldLength: 100     # 分離行動の回避角     @_separationAngle: 0     # 結合行動の回避角     @_cohesionAngle: 0 | 
パラメータのセッター
Controlerクラスに、Creatureクラス変数へのセッターを定義する。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 |   class Controler     .....     # 定数として扱うクラス変数を設定するメソッド群     setVMax: (vMax) -> Creature._vMax = vMax     setCreatureSize: (size) -> Creature._drawSize = size     setWallDetectionLength: (pix) -> Creature._wallDetectionLength =  pix     setWallRepulsionParam: (param) -> Creature._wallRepulsionParam = param     setViewFieldLength: (length) -> Creature._viewFieldLength = length     setSeparationAngle: (angle) -> Creature._separationAngle = angle     setCohesionAngle: (angle) -> Creature._cohesionAngle = angle     setIntervalSec: (@interval_sec) -> | 
パラメータのセット
HTMLで定義されたパラメータをControlerオブジェクトのセッターによってセットする。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # スクリプトが読み込まれた時の実行部分 jQuery ($) ->   # Controlerを作成し、canvasオブジェクトを渡す   canvas = $("#Boids22_canvas")[0]   controler = new Boids22.Controler(canvas)   # 固定パラメータのセット   # パラメータの値は、Javascript形式でHTMLに埋め込まれている想定   controler.setVMax(BD22_V_MAX)   controler.setCreatureSize(BD22_CREATURE_SIZE)   controler.setWallDetectionLength(BD22_WALL_DETECTION_LENGTH)   controler.setWallRepulsionParam(BD22_WALL_REPULSION_PARAM)   controler.setViewFieldLength(BD22_VIEW_FIELD_LENGTH)   controler.setSeparationAngle(BD22_SEPARATION_ANGLE)   controler.setCohesionAngle(BD22_COHESION_ANGLE)   controler.setIntervalSec(BD22_INTERVAL_SEC)   ..... | 
Ceatureクラスの変更 – cohesion()メソッドの追加
Creatureクラスのmove()メソッドがcohesion()メソッドを呼び出すようにする。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |   class Creature extends MovingAgent     .....     move: (interval_sec) ->       # 壁を避ける       @wallAvoidance()       # 分離行動(separation)       @separation()       # 結合行動(cohesion)       @cohesion()       ..... | 
coheion()メソッドを新たに定義する。
- 速度の方向を変化させる回転行列のcos、sinに対応したローカル変数cs、snを定義している
- 重心位置への参照がclusterCenterプロパティに保存されるが、視野内に個体が存在しないときはnullとなる
- 速度の回転方向は、右がマイナス方向、左がプラス方向となることに注意
| 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 |     # Boids2.2     # 結合行動(cohesion)     # 前方視角180度以内の全個体の重心に向かって速度を少し変更する     cohesion: ->       # 群のうち認識した個体の数とそのグループの重心       n = 0       clusterCenter = null       # 結合行動の方向転換計算用cos/sin       cs = Math.cos(Creature._cohesionAngle)       sn = Math.sin(Creature._cohesionAngle)       # 自分以外の群のすべての個体についてサーチ       for other in @cluster.creatures         if other != this           # 相手が自身の前方にいるなら、その位置を考慮           if other.isInFrontOf(this)             n++             if clusterCenter?               clusterCenter.plusEq(other.pos)             else               clusterCenter = new Vector(other.pos.x, other.pos.y)       # 前方の相手が1つでも存在すれば、結合行動をとる       if clusterCenter?         clusterCenter.divEq(n)         # 重心が自分の右にあれば左に、自分の左にあれば右に進路を変更         if clusterCenter.isOnTheRightOf(this)           vx =  @v.x * cs + @v.y * sn           vy = -@v.x * sn + @v.y * cs         else           vx = @v.x * cs - @v.y * sn           vy = @v.x * sn + @v.y * cs         @v.x = vx         @v.y = vy |