鳥の群れみたいな何か keno42 forked:4favorite:39lines:166license : MIT License modified : 2009-11-22 19:00:33 Embed Tweet package { import flash.display.Sprite; import flash.display.StageScaleMode; import flash.events.Event; import flash.geom.Point; [SWF(framerate=60, backgroundColor="#000000")] public class Boids extends Sprite { private const COUNT:int = 70; // 個体数 private const CHANGE_TARGET_RATE:Number = 0.02; // えさ場(?)変更の割合 private var firstBird:Bird = new Bird(); private var center:Point = new Point(); private var bg:Sprite = new Sprite(); // グリッド描画 private var birds:Sprite = new Sprite(); // みなさんの置き場 private var targetPoint:Point = new Point(); // えさ場(?)の場所 public function Boids() { stage.scaleMode = StageScaleMode.NO_SCALE; birds.x = 232; birds.y = 232; addChild( bg ); addChild( birds ); // 設置 birds.addChild(firstBird); var lastBird:Bird = firstBird; for (var i:int = 1; i < COUNT; i++ ) { var bird:Bird = new Bird(); lastBird.next = bird; lastBird = bird; birds.addChild(bird); } // 背景は黒くしとく this.graphics.beginFill(0); this.graphics.drawRect(0,0,465,465); // 背景グリッド(無駄に大きめ) bg.graphics.clear(); bg.graphics.lineStyle(0, 0x00FF00, 0.25); for ( var i:int = 0; i < 20; i++ ) { bg.graphics.moveTo(60*i, 0); bg.graphics.lineTo(60*i, 1000); bg.graphics.moveTo(0, 60*i); bg.graphics.lineTo(1000, 60*i); } changeTarget(); addEventListener(Event.ENTER_FRAME, onEnterFrame); } /** * 毎フレーム更新 */ private function onEnterFrame(e:Event):void { // えさ場(?)の変更 if ( Math.random() < 0.01 ) changeTarget(); // 中心位置とか計算用の初期化 center.x = 0; center.y = 0; var maxX:Number = -99999999999999999999; var minX:Number = 99999999999999999999; var maxY:Number = -99999999999999999999; var minY:Number = 99999999999999999999; // 工夫ゼロの2重ループなのでめちゃ重い。O(N^2) var currentBird:Bird = firstBird; do { var targetBird:Bird = firstBird; var nearestD:Number = 9999999999999999999999; do { if ( targetBird == currentBird ) continue; var targetX:Number = targetBird.x - currentBird.x; var targetY:Number = targetBird.y - currentBird.y; var distance:Number = targetX * targetX + targetY * targetY; if ( distance < nearestD ) { currentBird.nearestBird = targetBird; nearestD = distance; } } while ( targetBird = targetBird.next ) currentBird.nearestD = nearestD; center.x += currentBird.x; center.y += currentBird.y; if ( currentBird.x > maxX ) maxX = currentBird.x; if ( currentBird.x < minX ) minX = currentBird.x; if ( currentBird.y > maxY ) maxY = currentBird.y; if ( currentBird.y < minY ) minY = currentBird.y; } while ( currentBird = currentBird.next ) // 座標の加重平均 center.x /= COUNT; center.y /= COUNT; // 各自が行動を決定 currentBird = firstBird; do { currentBird.centerX = targetPoint.x; currentBird.centerY = targetPoint.y; currentBird.update(); // currentBird.nearestBird = null; // currentBird.nearestD = 0; } while ( currentBird = currentBird.next ) // カメラのスケール // var scale:Number = Math.min( 465 / (maxX - minX + 20), 465 / (maxY - minY + 20), 1 ); var scale:Number = 1; birds.scaleX += 0.1 * (scale-scaleX); birds.scaleY += 0.1 * (scale-scaleY); // カメラ中心の移動 birds.x += 0.1 * (232 - center.x - birds.x); birds.y += 0.1 * (232 - center.y - birds.y); // 背景グリッド描画 drawbg(); } private function changeTarget():void { targetPoint.x = Math.random() * 1500 - 750; targetPoint.y = Math.random() * 1500 - 750; } private function drawbg():void { var gridStartX:Number = (birds.x) % 60 - 300; var gridStartY:Number = (birds.y) % 60 - 300; bg.x = gridStartX; bg.y = gridStartY; } } } import flash.display.MovieClip; class Bird extends MovieClip { private const MAX_V:Number = 5; // 最大速度 private const MIN_V:Number = 1; // 最低速度 private const AVE_V:Number = 0.5 * (MAX_V - MIN_V) + MIN_V; private const V_RATE:Number = 0.1; // 速度変更時の掛け率 private const A_RATE:Number = 0.15; // 角度変更時の掛け率 private const FOLLOW_RATE:Number = 0.1; // 一番近いのに素直についていく確率 private const AVOID_ANGLE:Number = 0.5; // どのくらいあわてて避けるか? private var myColor:uint = Math.random() * 0xFFFFFF | 0x444444; public var angle:Number = 2 * Math.PI * Math.random(); public var velocity:Number = Math.random() * (MAX_V - MIN_V) + MIN_V; public var nearestD:Number; public var nearestBird:Bird; public var centerX:Number; public var centerY:Number; public var next:Bird; private const AVOID_DISTANCE:Number = Math.pow( 20 + 5 * Math.random(), 2); // 避ける距離 private const FOLLOW_DISTANCE:Number = Math.pow( 30 + 20 * Math.random(), 2); // ついていく距離 public function Bird() { this.x = Math.random() * 465 - 232; this.y = Math.random() * 465 - 232; this.mouseEnabled = this.mouseChildren = false; draw(); } /** * 初期描画 */ private function draw():void { this.graphics.beginFill(myColor); this.graphics.moveTo(0, -3); this.graphics.lineTo(5, 5); this.graphics.lineTo(-5, 5); this.graphics.lineTo(0, 3); this.graphics.endFill(); } /** * 座標更新 */ public function update():void { var targetVelocity:Number = AVE_V; var targetAngle:Number = Math.atan2( centerY - this.y, centerX - this.x ); if ( nearestD < AVOID_DISTANCE ) { // 避ける var nearestAngle:Number = Math.atan2( nearestBird.y - y, nearestBird.x - x ) - angle; nearestAngle %= 2 * Math.PI; var tempAngle:Number = (nearestAngle - angle) % ( 2 * Math.PI ); if ( tempAngle < 0 ) tempAngle += 2 * Math.PI; if ( nearestAngle < (0.5 * Math.PI) && nearestAngle > ( -0.5 * Math.PI ) ) { targetVelocity = MIN_V; if ( tempAngle < Math.PI ) targetAngle = angle + AVOID_ANGLE; else targetAngle = angle - AVOID_ANGLE; } else { targetVelocity = MAX_V; if ( tempAngle < Math.PI ) targetAngle = angle + AVOID_ANGLE; else targetAngle = angle - AVOID_ANGLE; } } else if ( nearestD < FOLLOW_DISTANCE ) { // そろえる targetVelocity = 0.8 * ( nearestBird.velocity ) + 0.2 * targetVelocity; targetAngle = (Math.random()<FOLLOW_RATE)?nearestBird.angle:targetAngle; } this.velocity += V_RATE * (targetVelocity - this.velocity); targetAngle -= angle; while ( targetAngle > Math.PI ) targetAngle -= 2 * Math.PI; while ( targetAngle < -Math.PI ) targetAngle += 2 * Math.PI; angle += A_RATE * targetAngle; this.x += Math.cos(angle) * velocity; this.y += Math.sin(angle) * velocity; this.rotation = angle * 180 / (Math.PI); /* // デバッグ用 一番近いやつに線を引く ( rotation = 0で固定すること ) this.graphics.clear(); draw(); this.graphics.lineStyle(0, 0xFFFFFF); this.graphics.moveTo(0, 0); this.graphics.lineTo(nearestBird.x - this.x, nearestBird.y - this.y); */ } } Code Fullscreen Preview Fullscreen qwertyui nenjiru applicott dex157 j000 hacker_97ryb.. saintw beta_chelsea.. imajuk shalaku tkinjo Mae_ITR sw_lucchini xor nyamogera kenz eternity_hir.. yamat Nyarineko paq buccchi Murai tristan osamX plankton skn kazmaro oreore 178ep3 matsumos greentec : sound sdfk : AL hacker_kszun.. : graphicslifeformbird attunedesign.. : flockingflocking nicoptere : boidsflockboids behaviour 1 class a440hlz : beautifl soundkitchen.. : ロート製薬ロート!ロートロート! 9re : 群 OKASUKE : Boids鳥の群れ AI AL Boids beautifl flock flocking graphics lifeform sound ロート製薬 Math.PI Point.distance mouseEnabled addChild mouseChildren rotation scaleY scaleX Math.atan2 Math.pow addEventListener Point MovieClip Math.random Math.cos Event.ENTER_FRAME Math.sin Event uint int sort new page view favorite forked pv130 forked from: 鳥の群れみたいな何か cute forked:0 favorite:1lines:166 (diff:1) pv615 forked from: 鳥の群れみたいな何か hacker_nf9cwadf forked:3 favorite:0lines:166 (diff:2) pv876 鳥の群れみたいだった何かを増量 keno42 forked:2 favorite:0lines:249 (diff:175) pv389 forked from: 鳥の群れみたいな何か fishKing forked:1 favorite:0lines:165 (diff:2)