スポンサーサイト
2008.09.08 | |
ActionScript勉強中。
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クラスについては後述します。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メソッドを実行します。// 個体の数まずinitメソッドでSwarmクラスのインスタンスを生成して、ソイツにBoidクラスのインスタンスを登録してマス。各Boidインスタンスのalignment/cohesion/separationプロパティに乱数を使った値を設定することで個体差を出しています。
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();
});
2007.09.23 | | Comments(0) | Trackback(0) | Flash CS3
遅ればせながらAdobe AIR update Beta 1 for Flash CS3 Professionalを試してみました。のでおぼえがき。
コレって何かというと、Flash CS3からフラッシュをAIRアプリケーションとしてパブリッシュできるようにするアップデートらしいデス。akihiro kamijoさんのAdobe AIR update for Flash CS3 Professional Beta 1 公開エントリで詳細に紹介なさってマス。
名前通りFlash CS3 Professionalのアップデートなので、Flash CS3 Professionalがインストールされていることが前提ぽいデス。
そんで、上記リンクの説明に従って、
2007.09.20 | | Comments(0) | Trackback(1) | Flash CS3
マウスカーソルの動きにあわせて曲線が変化するサンプルです。ゴムひもの端をつまんで動かすようなカンジ(?)です。
曲線はGraphics#curveToメソッドを使って描画しています。
サンプルではマウスカーソルの動きに連動する描画オブジェクトをいくつか用意して、そいつらの座標をコントロールポイント、2つのコントロールポイントの中点をアンカーポイントとしてcurveToメソッドを連続で使用しています。
中点をアンカーポイントにするのは、たしか「ActionScript 3.0 Animation」のcurveToのサンプルでやってたやり方だったと思います。
コントロールポイントとなる描画オブジェクトは、ターゲットとなる描画オブジェクトから一定の距離に減速しながら近づく動作をします。サンプルではコレをスプライトの派生クラスとして実装してみました。
package {
import flash.display.*;
import flash.events.*;
/**
* 減速しながらターゲットに近づくスプライト。
*/
public class Stalker extends Sprite {
/** ターゲット */
private var _target:DisplayObject;
/** ターゲットとの間に置く距離 */
private var _distance:Number;
/** 近づく速度係数 */
private var _speed:Number;
/**
* コンストラクタ
* @param target ターゲット
* @param distance ターゲットとの間に置く距離
* @param speed 速度係数
*/
public function Stalker(target:DisplayObject,
distance:Number = 0,
speed:Number = 2) {
_target = target;
_distance = distance;
_speed = speed;
// フレームイベントを登録
addEventListener(Event.ENTER_FRAME, doEnterFrame);
}
/**
* フレームイベントハンドラ。
* @param evt イベントオブジェクト
*/
public function doEnterFrame(evt:Event) {
// ターゲットまでの距離
var dx:Number = _target.x - evt.target.x;
var dy:Number = _target.y - evt.target.y;
var td:Number = Math.sqrt(dx * dx + dy * dy);
// 移動距離
var d:Number = (td - _distance) / _speed;
// 移動
evt.target.x += dx * d / td;
evt.target.y += dy * d / td;
}
}
}コンストラクタで追跡対象の描画オブジェクト/最終的に追跡対象との間に置く距離/速度係数を指定すると、それらのパラメータに合わせて減速しながら移動します。自身の位置を変更する処理はdoEnterFrameメソッドに記述していて、コレをENTER_FRAMEイベントリスナに登録しています。// ポイント間の距離最初にスプライトを一つ作成しています(target)。コレはマウスカーソルの位置に表示するスプライトです。先ほどのStalkerクラスを、指定したDisplayObjectを追跡するようにしたための措置デス。
var d:Number = 10;
// ポイント移動速度係数
var s:Number = 2;
// ポイント数
var point_cnt:int = 10;
// 先頭ポイント
var target:Sprite = new Sprite();
var g:Graphics = target.graphics;
g.beginFill(0x0000FF, 1.0);
g.drawCircle(0, 0, 2);
g.endFill();
target.visible = false;
addChild(target);
// ポイント配列
var point_array:Array = [target];
// 描画領域
var screen:Sprite = new Sprite();
addChild(screen);
// ポイント生成
for (var i:int = 0; i < point_cnt; i++) {
var stalker:Stalker = createPoint(point_array[i]);
addChild(stalker);
point_array.push(stalker);
}
// フレームイベントハンドラ
addEventListener(Event.ENTER_FRAME,
function(e:Event) {
// ターゲットを移動
target.x = stage.mouseX;
target.y = stage.mouseY;
// 曲線描画
drawCurve();
});
// クリックイベントハンドラ
addEventListener(MouseEvent.CLICK,
function(e:Event) {
for each (var p:Sprite in point_array) {
p.visible = !p.visible;
}
});
// ポイント生成メソッド
function createPoint(target:DisplayObject):Stalker {
var stalker:Stalker = new Stalker(target, d, s);
var g:Graphics = stalker.graphics;
g.beginFill(0x0000FF, 1.0);
g.drawCircle(0, 0, 2);
g.endFill();
stalker.visible = false;
return stalker;
}
// 曲線描画メソッド
function drawCurve() {
var g:Graphics = screen.graphics;
g.clear();
var p:Sprite = point_array[0];
var np:Sprite = point_array[1];
g.moveTo(p.x, p.y);
for (var i:int = 1, iEnd:int = point_array.length - 1;
i < iEnd;
i++) {
p = np;
np = point_array[i + 1];
g.lineStyle(1, 0x9999FF);
g.curveTo(p.x, p.y, (p.x + np.x) / 2, (p.y + np.y) / 2);
}
}
2007.09.13 | | Comments(0) | Trackback(2) | Flash CS3
« | HOME | »
Author:HundredthMonkey
プログラマ。