Forked from: ll_koba_ll's Boid diff:1 forked from: Boid HaraMakoto forked:0favorite:3lines:232license : All rights reserved modified : 2009-05-08 12:13:58 Embed Tweet // forked from ll_koba_ll's 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; } } Code Fullscreen Preview Fullscreen pikselek PESakaTFM sketchbookga.. : flockingghostlyparticlesspiritsflocking ghosts, neat flocking ghostly particles spirits clone Math.min Event.ADDED_TO_STAGE width Math.max height addEventListener Math.sqrt rotation Point StageAlign.TOP_LEFT align removeEventListener translate scaleMode unlock lock StageScaleMode.NO_SCALE graphics drawRect