Boid
package
{
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.filters.*;
import com.flashdynamix.utils.SWFProfiler;
[SWF(width="300", height="300", frameRate="30", backgroundColor="#000000")]
public class BoidSketch extends Sprite
{
private const FISH_NUM:int = 50;
private var _canvas:BitmapData;
private var _firstFish:Fish;
private var _fishView:FishView = new FishView();
private var _blurFilter:BlurFilter;
private var _tmpPoint:Point = new Point();
public function BoidSketch()
{
addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event):void
{
SWFProfiler.init(this);
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
removeEventListener(Event.ADDED_TO_STAGE, init);
_canvas = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0x00FFFFFF);
addChild(new Bitmap(_canvas));
var prevFish:Fish = new Fish();
_firstFish = prevFish;
// fishつくる
for (var i:int=0; i<FISH_NUM; i++)
{
prevFish.next = new Fish();
prevFish = prevFish.next;
prevFish.firstFish = _firstFish;
prevFish.stageWidth = _canvas.width;
prevFish.stageHeight = _canvas.height;
prevFish.x = Math.random()*_canvas.width;
prevFish.y = Math.random()*_canvas.height;
prevFish.vx = FishUtil.rangeRandom(-3, 3);
prevFish.vy = FishUtil.rangeRandom(-3, 3);
}
addEventListener(Event.ENTER_FRAME, loop);
_blurFilter = new BlurFilter(2,2);
}
private function loop(e:Event):void
{
var f:Fish = _firstFish;
_canvas.lock();
//_canvas.fillRect(_canvas.rect, 0x000000);
while((f = f.next) != null)
{
f.update();
var mtx:Matrix = new Matrix()
mtx.translate(f.x, f.y);
_canvas.draw(_fishView, mtx);
}
// ブラ-とってもおもろい
_canvas.applyFilter(_canvas, _canvas.rect, _tmpPoint, _blurFilter);
_canvas.unlock();
}
}
}
import flash.display.*;
import flash.geom.*;
class Fish
{
private const DIST_THRESHOLD1:int = 10;
private const DIST_THRESHOLD2:int = 20;
private const DIST_THRESHOLD3:int = 30;
private const FACTOR_CHOHESION:Number = 100;
private const FACTOR_SEPARATION:Number = 10;
private const FACTOR_ALINGMENT:Number = 10;
private const VELOCITY_LIMIT:Number = 3;
private var r1:Number = 1.0;
private var r2:Number = 0.8;
private var r3:Number = 0.1;
public function Fish()
{
}
public var next:Fish;
public var vx:Number = 0;
public var vy:Number = 0;
public var x:Number = 0;
public var y:Number = 0;
public var rotation:Number;
public var scale:Number;
public var stageWidth:Number = 0;
public var stageHeight:Number = 0;
public var firstFish:Fish;
private var p1:Point;
private var p2:Point;
private var p3:Point;
private var _tmpPoint:Point = new Point();
public function update():void
{
if (firstFish == null) return;
p1 = _tmpPoint.clone();
p2 = _tmpPoint.clone();
p3 = _tmpPoint.clone();
cohesion();
separation();
alignment();
vx += r1*p1.x + r2*p2.x + r3*p3.x;
vy += r1*p1.y + r2*p2.y + r3*p3.y;
limitVelocity();
x += vx;
y += vy;
if (stageWidth != 0)
{
if (x < 0)
{
x = stageWidth;
}
else if (x > stageWidth)
{
x = 0;
}
}
if (stageHeight != 0)
{
if (y < 0)
{
y = stageHeight;
}
else if (y > stageHeight)
{
y = 0;
}
}
}
private function limitVelocity():void
{
var v:Number = Math.sqrt(vx*vx + vy*vy);
if (v > VELOCITY_LIMIT)
{
vx = (vx/v)*VELOCITY_LIMIT;
vy = (vy/v)*VELOCITY_LIMIT;
}
}
// 効率悪い気がするけどとりあえず分かりやすく
// rule1 Cohesion
private function cohesion():void
{
var f:Fish = firstFish;
var len:Number = 0;
var count:int = 0;
while((f = f.next) != null)
{
if ( this != f)
{
len = FishUtil.dist(this, f);
if (len > DIST_THRESHOLD2 && len < DIST_THRESHOLD3)
{
p1.x += f.x;
p1.y += f.y;
count++;
}
}
}
if (count > 0)
{
p1.x /= count;
p1.y /= count;
p1.x = (p1.x - x) / FACTOR_CHOHESION;
p1.y = (p1.y - y) / FACTOR_CHOHESION;
}
}
// rule2 Separation
private function separation():void
{
var len:Number = 0;
var f:Fish = firstFish;
while((f = f.next) != null)
{
if (this != f)
{
len = FishUtil.dist(this, f);
if (len < DIST_THRESHOLD1)
{
p2.x -= (f.x - x)/FACTOR_SEPARATION;
p2.y -= (f.y - y)/FACTOR_SEPARATION;
}
}
}
}
// rule3 Alingment
private function alignment():void
{
var f:Fish = firstFish;
var len:Number = 0;
var count:int = 0;
while((f = f.next) != null)
{
if ( this != f)
{
len = FishUtil.dist(this, f);
if (len > DIST_THRESHOLD1 && len < DIST_THRESHOLD1)
{
p3.x += f.vx;
p3.y += f.vy;
count++;
}
}
}
if (count > 0)
{
p3.x /= count;
p3.y /= count;
p3.x = (p3.x - vx)/FACTOR_ALINGMENT;
p3.y = (p3.y - vy)/FACTOR_ALINGMENT;
}
}
}
class FishView extends Sprite
{
public function FishView()
{
var g:Graphics = graphics;
g.lineStyle(1, 0xFFFFFF);
g.drawRect(0,0,1,1);
g.endFill();
/*
g.moveTo(0,0);
g.lineTo(-15, 6);
g.lineTo(-15, -6);
g.lineTo(0,0);
*/
}
}
class FishUtil
{
public static function dist(f1:Fish, f2:Fish):Number
{
{
var dx:Number = f1.x - f2.x;
var dy:Number = f1.y - f2.y;
return Math.sqrt(dx*dx + dy*dy);
}
}
public static function rangeRandom(min:Number, max:Number):Number {
return Math.floor(Math.random()*(max-min+1))+min;
}
}