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オブジェクトのセッター群を呼び出している。

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です