Boids 1.x – コード説明

Boids 0.5

全体構成

Boidsを構築していくために、以下のような全体構成とした。

HTML
WordPressのテキストエディタで、入力やボタン、canvasなどの必要な要素を書き込む。
外部スクリプトファイル
各バージョンのBoidsを実行するための外部スクリプトファイルを用意する。バージョンごとにパッケージ化する。

HTML

個体数をセットするためのinput要素のタイプは”number”とした。こうすることにより、ボックスの右側に値をコントロールする矢印が出たり、最小値の指定などができる。

ボタンはWordPressでonclickを使うと問題が生じるので、HTMLでは単にボタンを表示させるだけとし、リスナについてはコード側で対応する。

canvas要素は書き方によってWordPressで勝手に変更されてしまうので注意。

input要素とcanvasについては、コード側から参照するためのidを付与している。

スクリプトについては、jQueryはWordPress側で読み込まれるとのこと。外部スクリプトファイルは、</body>タグの直前あたりを想定して、WordPressのテキストモードで最後尾にscript要素を書いた。<script type="..." src="..."></script>とテキストモードで書いても、ビジュアルモードを経由すると以下のように書き換えられてしまう。

  1. 勝手にCDATAのパターンが挿入され、間に改行が入ってしまう
  2. srcとtypeの指定順序が逆になってしまう

クラス構成

クラスは以下の4つを準備

  • Boidsの活動領域となるFieldクラス
  • 個々の個体を表現するCreatureクラス
  • 複数のCreatureが集まった群を表現するClusterクラス
  • 各オブジェクトを生成し、ボタン操作に対応してアニメーションをコントロールするControlerクラス

パッケージ

異なるバージョンのBoidsを同じページで動かすため、バージョンごとのパッケージに上記4つのクラスを入れることとした。

初めのバージョンに対応したパッケージ名はboids05で、グローバルにアクセスするのはControlerオブジェクトだけとし、Boids05.Controlerを定義している。

そして最後に、このスクリプトファイルが読み込まれたときにボタンに対するリスナを登録するための処理を記述している。

各ブロックとクラスの説明

リスナ登録

jQueryの構文を用いている。WordPressでjQueryを用いる場合、”$”が別のエイリアスに定義されているらしいので、1行目のように書くとのこと。

1つ目のブロックではcanvas要素のDOMオブジェクトを取得し、controlerオブジェクトを生成して初期値をセットしている。

この段階では速度関係は必要ないが、次のステップの前にとりあえず実装したため、Controler.setVMax()メソッドを読んでいる。

2つ目のブロックでは、ボタンが押されたときの処理を記述しており、numberボックスから値を読み込み、それに基づいて個体生成の指令を出している。

Controlerクラス

ブラウザ側からの指令と、スクリプト内の各クラスとの仲立ちを一手に引き受けるクラスで、この段階では以下の機能を提供する。

constructor
canvasオブジェクトを渡してControlerオブジェクトを生成する。
constructor(canvas)
canvasオブジェクトを渡してConstructorオブジェクトを生成する。
setVMax(vMax)
ランダムに生成する速さの最大値をConstructorオブジェクトにセットする。
createCreature()
位置と速度(速さと方向)をランダムに与えて個体を生成する。
generate(population)
指定した数の個体を生成し、Clusterオブジェクトに格納する。

Fieldクラス

将来の拡張も考慮して、一つのクラスとした。現時点では単なる矩形で、上下左右の座標値をプロパティに持つ。

Clusterクラス

Creatureオブジェクトを1~複数保持する「群」のクラス。提供する機能は以下の通り。

constructor(canvas)
個体を描画するcanvasを渡してClusterオブジェクトを生成。
clearCreatures()
群の個体を空にする。
addCreature(creature)
Creatureオブジェクトを渡し、群に追加する。
draw()
群の全ての個体を描画する。実際には、保持している個体のdraw()メソッドを呼び出しているだけ。

Creatureクラス

個々のクラスを表現するクラス。このバージョンでは運動はさせないが、速度関係のプロパティや初期化は行っている。

constructor(canvas)
Fieldオブジェクトを指定してCreatureオブジェクトを生成。
setPosition(x, y)
個体が存在する座標を指定。
setVelocity(vx, vy)
速度の成分をセット。このバージョンでは必要ないが実装。
draw(context)
描画コンテキストを指定して、個体を描画する。このバージョンでは単純な円を描いている。

Boids 1.0

HTML

Boids 1.0用のボックスやボタンを用意し、外部スクリプトファイルを読み込んでいる。

このバージョンから個体の運動をさせるので、Start/Stopボタンを追加している。

パッケージとクラスの変更

パッケージ構成

パッケージについては、パッケージ名やエイリアスを変更。

また、個体の運動を追加するため、以下のメソッドを追加。

  • Creature.move(interval_sec)
  • Cluster.move()
  • Controler.setIntervalSec(interva._sec)
  • Controler.startAndStop()

Creature.move()

秒単位のフレームタイムを指定して呼び出される。

  • 各個体の速度で等速度運動
  • 壁に当たった場合は全反射

Cluster.move()

秒単位のフレームタイムを指定し、群の個体の数の分だけCreature.move()メソッドを呼び出す。

Controlerクラス

変更内容は以下の通り。

プロパティ追加
アニメーションをコントロールするプロパティとして以下を追加。

  1. 運動中かどうかを保持するisRunningフラグ
  2. 作動中のintervalタイマを保持するtimer
  3. 秒単位のフレームタイムを保持するinterval_sec
setIntervalSec(interval_sec)
アニメーションのフレームタイムをセット。
startAndStop()
Start/Stopボタンを押すごとに、作動状態と停止状態を切り替え。特にリスナにコールバック関数を無名関数で登録するときに、thisをバインドするためのファットアローを使っていることと、無名関数で引数を表示する記法に留意。

 

Boids 1.1

このバージョンでは、個体を壁にぶつかってから全反射させるのではなく、壁が近づくとともに斥力を感じるように壁を避けようとする動作を導入する。

HTML

Boids 1.0用のボックスやボタンを用意し、外部スクリプトファイルを読み込んでいる。

パッケージとクラスの変更

パッケージ構成

クラス構成は特に変わらず、パッケージ名とエイリアスを本バージョンにあったものとする。以下のバージョンでも同じ。

Creatureのクラスプロパティ

このバージョンから、速度の最大値をControlerからCreatureのクラスプロパティに変更(6行目)。

また、壁の接近を認識する距離(_detectionLength)と回避加速度計算時のパラメータ(_repulsionParam)を定義。

Creature.move

認識距離以内に壁に近づき始めると、壁からの斥力を想定した加速度を計算し、速度を変更。

加速度は重力加速度をイメージし、距離の2乗に反比例させた。

boids11_wall_avoidance

そもそもピクセル単位の計算では最小でも距離の値が”1″となるため、重力モデルでは大きな加速度が出ない。ここでは_detectionLengthを長さの基準としたが、壁との距離に応じて自然に避けるような運動をさせるためにパラメータ(_repulsionParam)を導入しなければならなかった。

なお、速度ベクトルの値のキャップを判定する際に速度成分の符号を用いているが、Math.sign()はほとんどのブラウザで使えないため、「値/絶対値」で符号を得ている。

Controlerクラス

vMaxの変更のみ。

Boids 1.2

このバージョンで、以下の点を変更している。

  1. 座標単位のプロパティ定義・計算を、独自クラスgeom2d.Vectorで書き換え
  2.  描画サイズなど各種パラメータをHTMLで設定できるようにする
    • 各種パラメータをstaticなクラス変数とする
    • HTMLでグローバルな変数としてパラメータ群を設定
    • 実行時にControlerオブジェクトのセッターでパラメータ群を設定
  3. Creatureオブジェクトの形状を自由に設定可能にする

HTML

独自クラスパッケージファイルの読み込み

本体のスクリプトファイルに先立って、独自クラスのパッケージファイル(taustation_geom2d.js)を読み込ませている。

パラメータ群の設定

HTMLのscript要素でパラメータ用のグローバル変数を定義する。これらはその後に読み込まれたスクリプトで利用される。

script要素内の変数定義はJavascriptで書くため、行末にコロン(;)をつけている。

script要素をWordPressのテキストモードで書くと、ビジュアルモードを経由したときに//<![CDATA[~改行~//]]>が挿入される。

また、Javascriptをscript要素に直接書くと、改行が除かれて一行になってしまう。

パッケージの準備とクラスの変更

Vectorクラスの利用

独自クラスgeom2d.Vectorを使って、位置・速度・加速度のコーディングを見やすくした。

各オブジェクトの生成と計算時にVectorオブジェクトを生成するnew演算子が介在するが、400個体程度の計算でもパフォーマンスの問題は見られなかった。

個体の形

これまではdraw()メソッドの中で直接円を描いていたが、今回はヘルパーメソッドdrawShape()を実装。

パラメータ設定

HTML内のスクリプト要素で定義されたグローバル変数を参照し、パラメータとしてクラス変数に格納。

この操作はControlerクラスに集約した。

変更に関係する箇所

Creatureクラスのクラス変数

@var: valの形式でクラス変数として定義。

Creatureの基本メソッド

これまでx, y, vx, vyのように個別の座標値で扱っていたプロパティを、Vectorクラスで置き換える。

 Creature.draw()

単純な円ではなく、方向を持った細長い三角形を描くように変更。

下図のように、基準点(x, y)から速度ベクトルの方向に頂点を、速度ベクトルと直角な報告に底辺を描く。ここで0 < p < 1で、これによって三角形の細長さが決まる。

boids12_shape1

ここでs_x = s(v_x / v) , \: s_y = s(v_y /v)と置くと下図のようになる。

boids12_shape3

コードは以下の通り。

Creature.move()

Vectorオブジェクトの導入に対応して書き直した。

斥力加速度計算のパラメータ(Creature._wallRepulsionParam)は()の外に出した。

Clusterクラス

変更箇所はない。

Controlerクラスのセッター

以下のメソッド群で整理。Creatureのクラス変数をセットしている。

実行部分

Controlerオブジェクトのセッター群を呼び出している。

 

CoffeeScript – Boids 1.x – 準備

Boids構築の準備

ここでは、以下のバージョンに沿って、Boidsの準備段階のコードを組み立てていく。

  1. Boids 0.5~ブラウザ上で指定した数の個体を表示させる
  2. Boids 1.0~個体を運動させる
  3. Boids 1.1~各個体が壁との衝突を避けるようにする
  4. Boids 1.2~個体の形をそれらしくする(内部的には独自クラスを導入)

Boids 0.5~個体の発生と表示

概要

まずスタートアップとして、指定された数の個体を発生・表示させるという簡単な枠組みを作る。

仕様は以下の通り。

  • numberボックスで個体数を指定
  • “GENERATE”ボタンを押すとcanvasに指定した数の個体が表示される
    • 個体の位置はその都度ランダムに設定される

デモンストレーション




コード詳細

Boids 0.5のコード説明へ

Boids 1.0~個体を動かす

概要

発生させた個体を表示させると同時に運動させる。

仕様は以下の通り

  • Numberボックスで個体数を指定
  • GENERATEボタンを押すとcanvasに指定した数の個体が表示される
    • 個体の位置はランダム
  • START/STOPボタンを押すたびに、各個体の運動と停止が切り替わる
    • 個体のスピードは一定の範囲内でランダムに設定され、スピードは変化しない
    • 壁に当たった場合は全反射する

デモンストレーション


 

コード詳細

Boids 1.0のコード説明へ

Boids 1.1~壁を避ける

概要

各個体が壁をよける動作を導入。壁からの距離に応じた斥力を想定し、それに応じた加速度を計算している。

操作方法はこれまでのものと同じ。

デモンストレーション


 

コード詳細

Boids 1.1のコード説明へ

Boids 1.2~Vectorの利用と個体の形

概要

このバージョンでは2つのことを導入している。

  • 一つは独自クラスのgeom2d.Vectorを利用していること
  • 今一つは個体の形を単純な円から任意の形とできるよう変更したこと

操作方法はこれまでのものと同じ。

デモンストレーション


 

コード詳細

Boids 1.2のコード説明へ






CoffeeScript – Boids

Boidsとは

Boidsは鳥や魚が群をなして移動する様をシミュレートするもので、概要はこちらにまとめている

一つ一つの個体は、一定の行動規範に従って「自律的に」動いていながら、全体が群として整然と運動することを再現する。

CoffeeScriptによるBoidsの開発

以下のステップで開発を進める。

  1. Boids 1.xのシリーズで、個体の生成・表示、運動、壁の回避などを実装
  2. Boids 2.xのシリーズで、最もシンプルな運動ルールを個体に与える
  3. Boids 3.xのシリーズで、「敵」を導入する
  4. アプリケーション版

 

Boids 2.x (JavaScript)

概要

Boids 1.3までで、基本的な個体の運動ルールを設定して群の動きを実現した。

これに対して、ルールの条件を変えて、それらが群の挙動に与える影響を見てみる。

Boids 2.0~引力と斥力の導入

考え方

Boids 1.3の基本的なコードでは、3つのルールについて、位置座標を元にした幾何的な計算で速度を変更したが、ここで結合と分離に対して引力・斥力の概念を導入する。

重力や正電気力は距離の自乗に反比例するが、この形で試したところ、かなり距離が近づくまで反応せず、近い距離になって急に力が強くなるため、挙動が不安定な傾向となった。

そこで、ここでは距離に反比例した引力・斥力が個体間に働くものとし、近傍距離以内では斥力が、それより遠く一定距離以内であれば引力が働くものとした。

挙動と考察

その挙動は、若干の振動があるものの基本コードと似ており、基本コードに対して、個体間の距離がより均等に近くなっている。心理的な行動が物理法則と類似である可能性を示唆している。

デモンストレーション

Boids 2.0を新しいタブで実行

Boids 2.1~直近個体に追随

考え方

結合と分離の実装は上記のまま、整列の条件を、直近の一個体の速度に追随するようルールを変更した。

挙動と考察

各個体が集まるのが極めて速く、群が密集状態になる。

また、群を形成してからのは振動を繰り返すのみで、、群全体としての移動は鈍い。

日常生活でも、近くの一人のみに注意して歩こうとすると却ってスムーズに移動できないことが多いが、これを示唆している。

デモンストレーション

Boids 2.1を新しいタブで実行

Boids 2.2~周辺個体に追随

考え方

整列のために追随するのが直近一個体では「近視眼的」なため、一定距離内の個体群の平均速度に追随するように変更。

挙動と考察

一個体のみに追随するよりも群として移動しやすくなるが、それほど大きな効果はなく、個体数が多くなるに従って(このケースでは個体数が15~20程度以上で)群として振動状態に入りやすくなる。

直近1個体でないとしても、周辺の動きだけに合わせると整然とした動きになりにくいことを示唆している。

デモンストレーション

Boids 2.2を新しいタブで実行

Boids 2.3~リーダーに追随

考え方

特定の一つの個体がリーダーとしてふるまい、他の個体はリーダーにのみ追随するルール。リーダーは他の個体のようなルールに従わないとしている。

挙動と考察

当然ながら、群の行動はリーダーの動きのみに追随して比較的なめらかになる。さらに、群全体が広がりを持つのも特徴。「雁行」を想起させる。

デモンストレーション

Boids 2.3を新しいタブで実行


前の記事:基本コード

 

Boids 1.x (JavaScript)

概要

Boids 1.0で準備した枠組みに、分離(Separation)、結合(Cohesion)、整列(Alignment)のルールを適用していく。

Boids 1.1~分離の導入

個体が近づいたときに、互いに近づき過ぎないように速度を修正するルールを導入。

デモンストレーション

Boids 1.1を新しいタブで実行

各個体が他の個体とぶつからないよう避けながらランダムに移動している。

グローバル定義部

個体同士が近づきすぎた場合の分離行動に入る最大距離を指定。

Creatureクラス

分離行動は個体のmove()メソッド内で実装し、相手との距離が大きいほど逆方向への力をかける。速度調整後、速さを初期設定の値にそろえる。

Boids 1.2~結合(Cohesion)の導入

分離に加えて、各個体が群として集まろうとするルール。具体には、群の中心に向かおうと速度を変更するルールを導入。

デモンストレーション

Boids 1.2を新しいタブで実行

個体がランダムに移動しながら、群を形成しようとしている。

グローバル定義部

まず、群の中心をグローバル変数として保持。

中心に向かって速度を変更する度合いを定数で指定。この値が小さいほど素早く、大きいほどゆるやかに群れようとする。

結合とのバランスで、分離の判定距離を小さめの値に設定している。

群の中心の算出

各個体が目指す群の中心を、実行関数moveAll()の中で計算する。ここでは、全個体の平均重心を群の中心としている。

Creatureクラス

結合行動も個体のmove()メソッド内で実装する。群の中心に向かって行くよう速度を変更。

ルールの適用準は、衝突回避を後にするため、結合→分離の順としている。

Boids 1.3~整列(Alignment)の導入

一通りのBoidsの実装の最終段階。

各個体が、群全体の移動方向に合わせようとするルールを導入。各個体が、自分の速度を群の全個体の平均速度に近づけようとする。

デモンストレーション

個体数

各個体が集まりながら「なんとなく」一定方向に動こうとしている。個体数が200程度と多くなると、群としての動きは鈍くなる。このとき、各個体が全く均等になるのではなく、数個程度集まって移動するさまが見られるのは興味深い。

グローバル定義部

整列の際の速度変更の度合いを指定する。この値が小さいほど素早く整列しようとする。

群の平均速度の算出

moveAll()関数を変更し、群の中心の算出に続いて平均速度を求める。

Creatureクラス

整列のルールを個体のmove()メソッドに実装する。

ルール適用の順番は、結合→整列→分離。これは一般に想定される生物の行動形態、「集まろうとする→一緒の方向に向かおうとする→衝突を避ける」と符合している。


前の記事:枠組みの準備

次の記事:条件と挙動のバリエーション


 

Boids 1.0 (JavaScript)

概要

BoidsをJavaScriptで再現するために、基本コードの枠組みとなるコード準備する。

  • 指定した下図の個体を発生させる
  • ボタン操作で各個体の動作を開始・停止する
  • 個体の動作は同じ速さでランダムな方向に動く

基本の動作から始めて順次拡充していくが、以後共通する仕様は以下の通り。

  • グローバル定義
    • HTML5のcanvasで描画することとし、canvasとそのコンテキストをグローバルオブジェクトとする
    • その他、個体や群れの挙動に係るパラメータもグローバル定義する
  • 個体のクラスCreature
    • move()メソッドは、個々のCreatureインスタンスの一定時間後の位置をその現在位置と速度から決定し、新しい位置に変更する
    • draw()メソッドは個々のCreatureインスタンスをcanvasに描く
    • 初期段階から、Boidsの3つのルールに対応するメソッドの枠のみ用意し、順次実装していく
  • Boidsの実行
    • 個体クラスのインスタンスをランダムな位置に複数発生させ、配列に格納する
    • 以下を繰返す
      • 現在位置の全てのCreatureオブジェクトをdrawAll()関数で描画
      • 一定時間間隔で全てのCreatureオブジェクトの位置をmoveAll()関数で変更する
      • moveAll()の中で3つのルールに対応する関数を呼び出すが、初期段階では枠のみ用意し、順次実装していく

仕様

以下の仕様で、個体とその群の生成、基本動作のみを実装する。

  • 操作
    • ブラウザのテキストボックスに個体数を入力
    • ボタンを押すごとに起動・停止を繰り返す
  • 初期設定
    • 初期状態で、ランダムな位置に個体を生成
    • 各個体の速さは一定とし、速度ベクトルの向きはランダムに与える
  • 挙動
    • 各個体は与えられた速度で移動
    • 上下左右の壁に当たった時は全反射
    • 個体間の干渉は考慮しない(重なりを許す)

デモンストレーション

個体数

スクリプトの内容

グローバル定義部

アプリケーション全体で保持・利用する変数・オブジェクトを定義。

Creatureクラス

一つ一つの個体を表すCreatureクラスを以下の様に構築する。これらのコンストラクタやメソッドは、以後の拡張を通して変わらない。

コンストラクタ

コンストラクタは、Creatureクラスのインスタンスを生成する。Creatureオブジェクトは、個々の座標と速度ベクトルの要素を保持する。

位置と速度のセッター

位置座標、速度ベクトルの要素を個体にセットする。

描画メソッド

自身をcanvasに描画する。ここでは位置座標を中心とする小円を描いている。canvasのコンテキストはグローバル変数contextに設定されている前提。

移動メソッド

与えられた速度で移動する。上下・左右の壁に当たった時の反射処理を行っている。

実行関数群

以下の関数群のうち、createCreatures()はボタンが押されるたときに与えられた数の個体を生成。

boids()はボタンが押されるたびに実行・停止を切り替える。

他の関数は、実行時に群全体を異動させ、描画するための関数。

createCreatures()~個体の生成

与えられた数の個体をCreatureインスタンスとして生成し、グローバルな配列に格納する。

boids()~メイン関数

ボタンが押されるたびに呼び出され、全体の実行/停止を制御する。

動画処理

タイマーにより個体を動かし、描画する。呼び出されるたびに、全ての個体を移動させ、描画する関数を呼び出す。

個体の移動

配列に格納された個体に移動を指示する。

個体の描画

配列に格納された個体に描画を指示する。


次の記事:基本コード

 

Boids – 群れの再現

概要

ボイド(Boids)は、アメリカのアニメーション・プログラマCraig Raynoldsが考案した人工生命シミュレーションプログラム。名称は鳥もどき(bird-oid)に由来。

多数の個体からなる群において、各個体の行動ルールを定めておき、一定のランダム性のもと自由に行動させる。個体が単純なルールに基づいて動きながら、群全体としてまとまった動きが再現される。

ルール

Boidsのルールとして、一般に以下の3項目が適用される。

分離(Separation)
他の個体とぶつからないように距離をとる。
結合(Cohesion)
群れの中心方向へ向かうように方向を変える。
整列(Alignment)
他の個体群と概ね同じ方向に飛ぶように速度と方向を合わせる。

群を構成する個体は、それぞれ独自の位置・速度を持って動きながら、上記3つのルールに従うことによって、群としての行動をとるようになる。

デモンストレーション

CoffeeScript

JavaScriptよりすっきりと書けるCoffeeScriptで、より遊べるものを作っていった。この過程で、CoffeeScript/JavaScriptの変数のスコープだとかパッケージの考え方だとかが勉強になった。

JavaScript

JavaScriptに慣れるために作ったプログラム群。