スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

--.--.-- | | スポンサー広告

群れっぽい動き

12個の円が虫の群れっぽい動きでマウスカーソルを追いかけるサンプルです。





この手の群れを表現するのにはBoid理論というのをよく使うそーで、このサンプルも一応それらしい作りにしています。

Boidでは、個体にSeparation/Alignment/Cohesionの3つのルールに基づく動きをつけることで全体として群れになるようにします。

Separationは各個体を分離するルールで、近づきすぎたら距離をとる。というのが基本みたいデス。

Alignmentは個体を整列させるルールで、個体が群れ全体の動きにつられるというカンジです。

Cohesionは群れを結束させるルールで、各個体が群れに収まろうとする動きデス。

このサンプルでは、上記ルールに基づいた3つのベクトルをフレーム毎に算出し、現在の動きを示すベクトルと算出した3つのベクトルを合成することで次の動きを決定しています。

この計算と合成はBoidクラスでやっています。BoidクラスはSpriteを継承したクラスで、画面上では色のついた円デス。ソースコードはこんなカンジです。

package {
import flash.display.*;
/**
* 群れを構成する個体クラス。
*/
public class Boid extends Sprite {
/** 慣性係数 */
private var _inertia:Number = 1;
/** 分離係数 */
private var _separation:Number = 30;
/** 整列係数 */
private var _alignment:Number = 0.6;
/** 結束係数 */
private var _cohesion:Number = 0.4;
/** x方向の移動ベクトル */
private var _vx:Number = 0;
/** y方向の移動ベクトル */
private var _vy:Number = 0;
/**
/**
* コンストラクタ。
*/
public function Boid() {
}
/**
* 分離係数を設定します。
* @param value 分離係数
*/
public function set separation(value:Number):void {
_separation = value;
}
/**
* 整列係数を設定します。
* @param value 整列係数
*/
public function set alignment(value:Number):void {
_alignment = value;
}
/**
* 結束係数を設定します。
* @param value 結束係数
*/
public function set cohesion(value:Number):void {
_cohesion = value;
}
/**
* x方向の移動ベクトルを戻します。
* @return x方向の移動ベクトル
*/
public function get vx():Number {
return _vx;
}
/**
* y方向の移動ベクトルを戻します。
* @return y方向の移動ベクトル
*/
public function get vy():Number {
return _vy;
}
/**
* 群れの個体として振舞わせます。
* @param swarmInfo 群れ情報
*/
public function behave(swarmInfo:Object):void {
var sv:Object = doSeparation(swarmInfo.boid_array);
var av:Object = doAlignment(swarmInfo.vx, swarmInfo.vy);
var cv:Object = doCohesion(swarmInfo.x, swarmInfo.y);
_vx = (_vx * _inertia + sv.x + av.x + cv.x) / 4;
_vy = (_vy * _inertia + sv.y + av.y + cv.y) / 4;
x += _vx;
y += _vy;
}
/**
* 分離する動作
* @param boid_array 個体の配列
* @return 移動ベクトル
*/
private function doSeparation(boid_array:Array):Object {
var t2:Number = _separation * _separation;
var dx:Number = 0;
var dy:Number = 0;
// 近傍の個体の重心を算出
var tx:Number = 0;
var ty:Number = 0;
var near_array:Array = new Array();
for each (var boid:Boid in boid_array) {
if (boid == this) {
continue;
}
dx = boid.x - x;
dy = boid.y - y;
if (dx * dx + dy * dy < t2) {
near_array.push(boid);
tx += boid.x;
ty += boid.y;
}
}
var cnt:int = near_array.length;
if (cnt == 0) {
return {x:0, y:0};
}
tx /= cnt;
ty /= cnt;
dx = x - tx;
dy = y - ty;
var d:Number = Math.sqrt(dx * dx + dy * dy);
return {x:dx * (_separation - d) / d, y:dy * (_separation - d) / d};
}
/**
* 整列する動作
* @param sx x方向の群れの移動ベクトル
* @param sy y方向の群れの移動ベクトル
* @return 移動ベクトル
*/
private function doAlignment(sx:Number, sy:Number):Object {
return {x:sx * _alignment, y:sy * _alignment};
}
/**
* 結束する動作
* @param cx 重心のx座標
* @param cy 重心のy座標
* @return 移動ベクトル
*/
private function doCohesion(cx:Number, cy:Number):Object {
return {x:(cx - x) * _cohesion, y:(cy - y) * _cohesion};
}
}
}
behaveメソッドを実行すると、分離/整列/結束の3つのベクトルを算出して、ソレらと現在のベクトルからx/yプロパティを更新します。behaveメソッドのパラメータswarmInfoは群れ自体の情報デス。コイツは群れを表現するSwarmクラスで作成してます。Swarmクラスについては後述します。

doSeparationメソッドが分離ベクトルを算出するメソッドです。設定された距離よりも近くに他の個体がいた場合、ソイツラから遠ざかるようにベクトルを算出してます。よりそれらしい動きにするには距離だけじゃなくて視界の範囲(角度)を設定したりもするようです。

doAlignmentメソッドが整列ベクトルを算出するメソッドです。群れ全体が一定の向きを持つためのルールですが、このサンプルではマウスカーソルを追いかけることになってるので、群れの重心からマウスカーソルへ向かうベクトルを基準にしています。

doCohesionメソッドが結束ベクトルを算出するメソッドです。群れの重心に向かうベクトルで、どの程度向かうのかはパラメータで設定します。

次は群れ自体をあらわすSwarmクラスです。コイツもSpriteの継承クラスにしています。先ほどのBoid#behaveメソッドは実際にはSwarmクラスのメソッドから呼び出されマス。
package {
import flash.display.*;
/**
* 群れクラス。
*/
public class Swarm extends Sprite {
/** 個体の配列 */
private var _boid_array:Array;
/** 群れの情報 */
private var _swarmInfo:Object;
/**
* コンストラクタ。
*/
public function Swarm() {
_boid_array = new Array();
_swarmInfo = new Object();
}
/**
* 群れに個体を追加します。
*/
public function addBoid(boid:Boid):void {
_boid_array.push(boid);
addChild(boid);
}
/**
* ターゲットの座標を指定して群れを動かします。
* @param targetX ターゲットのx座標
* @param targetY ターゲットのy座標
*/
public function behave(targetX:Number, targetY:Number):void {
var cnt:int = _boid_array.length;
// 個体の重心位置と平均移動ベクトル
var ax:Number = 0;
var ay:Number = 0;
for each (var boid:Boid in _boid_array) {
ax += boid.x;
ay += boid.y;
}
ax /= cnt;
ay /= cnt;
_swarmInfo.x = ax;
_swarmInfo.y = ay;
// 整列ベクトル
_swarmInfo.vx = targetX - ax;
_swarmInfo.vy = targetY - ay;
// 個体配列
_swarmInfo.boid_array = _boid_array;
// 個体を振舞わせる
for each (boid in _boid_array) {
boid.behave(_swarmInfo);
}
}
}
}
Swarmクラスは群れに属する個体の配列を持っていて、behaveメソッドを実行するとその群れに所属する全個体のbehaveメソッドを実行します。

Boid#behaveメソッドを実行するにあたって、群れ自体の情報swarmInfoを生成します。コイツはプロパティとして、群れの重心位置(全個体の座標の平均デス)/群れの重心からマウスカーソルに向かうベクトル/群れに属する個体の配列を持ちます。この情報を使って各個体は振る舞いを決定します。

んで、コイツラを使うフレームアクションはこうなってマス。
// 個体の数
var cnt:int = 12;
// 群れオブジェクトの生成
var swarm:Swarm;
// 初期化
init();
// 初期化処理
function init() {
if (swarm) {
removeChild(swarm);
}
swarm = new Swarm();
addChild(swarm);
// 個体の生成
for (var i:int = 0; i < cnt; i++) {
var boid:Boid = new Boid();
boid.x = Math.random() * stage.stageWidth;
boid.y = Math.random() * stage.stageHeight;
boid.alignment = Math.random() * 0.2 + 0.1;
boid.cohesion = Math.random() * 0.2 + 0.3;
boid.separation = Math.random() * 10 + 20;
// 個体を円で表示する
var g:Graphics = boid.graphics;
g.beginFill(Math.random() * 0xFFFFFF + 1, 1.0);
g.drawCircle(0, 0, 6);
g.endFill();
boid.filters= [new BlurFilter(4, 4)];
swarm.addBoid(boid);
}
}
// フレームアクション
addEventListener(Event.ENTER_FRAME,
function (e:Event) {
swarm.behave(mouseX, mouseY);
});
// クリックアクション
stage.addEventListener(MouseEvent.CLICK,
function (e:Event) {
init();
});
まずinitメソッドでSwarmクラスのインスタンスを生成して、ソイツにBoidクラスのインスタンスを登録してマス。各Boidインスタンスのalignment/cohesion/separationプロパティに乱数を使った値を設定することで個体差を出しています。
また、Boidクラス自体は描画内容を持たないので、ランダムな色の円をココで描画しています。

フレームアクションではSwarmインスタンスのbehaveメソッドを実行しています。これによってフレーム毎に各個体の振る舞いが実行されます。

またステージをクリックしたら、初期化しなおすようにしています。
スポンサーサイト

テーマ:Flash - ジャンル:コンピュータ

2007.09.23 | | Comments(1) | Trackback(1) | Flash CS3

コメント

管理人のみ閲覧できます

このコメントは管理人のみ閲覧できます

2008-12-11 木 13:51:55 | | # [ 編集]

コメントの投稿


秘密にする

トラックバック

http://100th.blog96.fc2.com/tb.php/37-f5518dc9
この記事にトラックバックする(FC2ブログユーザー)

[作ったよ][Flash]群れで染色体を書いてみた

いまは無きInfobar2に捧ぐ 正しくは染色体のような何かを書かせた、ですね。作成にあたりSpark projectのConvertColorというライブラリ(MITライセンス)を使わせていただきました。動きは、人様の「群れ」のソースをほぼそのまま借用(叱ってやって下さい)。そのうち自分で

2008.12.11 | dasign の Flash にっき

«  | HOME |  »

プロフィール

Author:HundredthMonkey
プログラマ。

ブロとも申請フォーム

この人とブロともになる

メールフォーム

名前:
メール:
件名:
本文:

ブログ内検索


上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。