In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

forked from: 鳥の群れみたいな何か

/**
 * Copyright cute ( http://wonderfl.net/user/cute )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/fZeN
 */

// forked from keno42's 鳥の群れみたいな何か
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);
        */
    }
}