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

Boid Simulation

Get Adobe Flash player
by linktale 28 May 2012
/**
 * Copyright linktale ( http://wonderfl.net/user/linktale )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/5kz1
 */

/*
Boid Simulation
鳥の群集運動とかに使う理論
・Separation(引き離し)
・Alingment(整列)
・Cohesion(結合)

元ソース:http://mrdoob.github.com/three.js/examples/canvas_geometry_birds.html

http://linktale.net/
*/

package {
    import com.flashdynamix.utils.SWFProfiler;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Matrix3D;
    import flash.geom.PerspectiveProjection;
    import flash.geom.Vector3D;

    [SWF(backgroundColor="0xffffff", frameRate="50", width="465", height="465")] 

    public class Trick extends Sprite { 
        private var SCREEN_WIDTH:Number, SCREEN_HEIGHT:Number, SCREEN_WIDTH_HALF:Number, SCREEN_HEIGHT_HALF:Number;
        private var camera:Camera3D, bird:Object3D, birds:Vector.<Object3D>, boid:Boid, boids:Vector.<Boid>;
        private var perspective:PerspectiveProjection
        
        public function Trick() { 
            //SWFProfiler.init(stage, this);
            Wonderfl.disable_capture();
            init();
        } 
        
        private function init():void {
            SCREEN_WIDTH = stage.stageWidth;
            SCREEN_HEIGHT = stage.stageHeight;
            SCREEN_WIDTH_HALF = SCREEN_WIDTH  / 2;
            SCREEN_HEIGHT_HALF = SCREEN_HEIGHT / 2;
            
            camera = new Camera3D();
            birds = new Vector.<Object3D>();
            boids = new Vector.<Boid>();
            
            for (var i:uint = 0; i < 100; i++ ) {
                boid = boids[i] = new Boid();
                boid.position.x = Math.random() * 400 - 200;
                boid.position.y = Math.random() * 400 - 200;
                boid.position.z = Math.random() * 400 - 200;
                boid.velocity.x = Math.random() * 2 - 1;
                boid.velocity.y = Math.random() * 2 - 1;
                boid.velocity.z = Math.random() * 2 - 1;
                boid.setAvoidWalls( true );
                boid.setWorldSize( 180, 180, 280 );
                
                bird = birds[i] = new Object3D(camera);
                bird.worldMatrix3D.position = boids[i].position;
                addChild(bird);
            }
            
            stage.addEventListener(Event.ENTER_FRAME, update);
            stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMove);
        }
        
        private function update(e:Event=null):void {
            for ( var i:uint = 0; i< birds.length; i++ ) {
                boid = boids[ i ];
                boid.run( boids );
                
                bird = birds[ i ];
                bird.worldMatrix3D.appendRotation(Math.atan2( - boid.velocity.z, boid.velocity.x ), Vector3D.Y_AXIS);  
                bird.worldMatrix3D.appendRotation(Math.asin( boid.velocity.y / boid.velocity.length ), Vector3D.Z_AXIS);  
                bird.worldMatrix3D.position =  boid.position;
                bird.world.z = boid.position.z;
                bird.world.alpha = ( 300 - bird.worldMatrix3D.position.z ) / 200;
                
                bird.update();
            }
        }
        
        private function mouseMove(e:MouseEvent):void {
            var vector:Vector3D = new Vector3D(stage.mouseX - SCREEN_WIDTH_HALF, -stage.mouseY + SCREEN_HEIGHT_HALF, 0)
            
            for ( var i:uint = 0; i < boids.length; i++ ) {
                boid = boids[ i ];
                vector.z = boid.position.z;
                boid.repulse( vector );
            }
        }
    }
}


import flash.geom.Vector3D;
class Boid {
    public var position:Vector3D, velocity:Vector3D;
    private var vector:Vector3D, acceleration:Vector3D;
    private var width:Number = 480, height:Number = 480, depth:Number = 200, goal:Vector3D, neighborhoodRadius:Number = 100;
    private var maxSpeed:Number = 4, maxSteerForce:Number = 0.1, avoidWalls:Boolean = false;
    
    public function Boid():void {
        init();
    }
    
    private function init():void {
        position = new Vector3D();
        velocity = new Vector3D();
        vector = new Vector3D();
        acceleration = new Vector3D();
    }
    
    public function setGoal(target:Vector3D):void {
        goal = target;
    }
    
    public function setAvoidWalls(val:Boolean):void {
        avoidWalls = val;
    }
    
    public function setWorldSize(width:Number, height:Number, depth:Number):void {
        this.width = width;
        this.height = height;
        this.depth = depth;
    }
    
    public function run(boids:Vector.<Boid>):void {
        if ( avoidWalls ) {
            vector = new Vector3D( -width, position.y, position.z );
            vector = avoid( vector );
            vector.scaleBy( 5 );
            acceleration.incrementBy( vector );
            
            vector = new Vector3D( width, position.y, position.z );
            vector = avoid( vector );
            vector.scaleBy( 5 );
            acceleration.incrementBy( vector );
            
            vector = new Vector3D( position.x, -height, position.z );
            vector = avoid( vector );
            vector.scaleBy( 5 );
            acceleration.incrementBy( vector );
            
            vector = new Vector3D( position.x, height, position.z );
            vector = avoid( vector );
            vector.scaleBy( 5 );
            acceleration.incrementBy( vector );
            
            vector = new Vector3D( position.x, position.y, -depth );
            vector = avoid( vector );
            vector.scaleBy( 5 );
            acceleration.incrementBy( vector );
            
            vector = new Vector3D( position.x, position.y, depth );
            vector = avoid( vector );
            vector.scaleBy( 5 );
            acceleration.incrementBy( vector );    
        }
        
        checkBounds();
        
        if ( Math.random() > 0.5 ) {
            flock( boids );
        }
        
        move();
    }
    
    private function flock(boids:Vector.<Boid>):void {
        if ( goal ) {
            acceleration.incrementBy( reach( goal, 0.005 ) );
        }
        acceleration.incrementBy( alignment( boids ) );
        acceleration.incrementBy( cohesion( boids ) );
        acceleration.incrementBy( separation( boids ) );
    }
    
    private function move():void {
        velocity.incrementBy( acceleration );

        var l:Number = velocity.length;
        if ( l > maxSpeed ) {
            velocity.scaleBy( 1 / (l / maxSpeed) );
        }

        position.incrementBy( velocity );
        acceleration = new Vector3D();
    }
    
    private function checkBounds():void {
        if ( position.x > width ) position.x = -width;
        if ( position.x < -width ) position.x = width;
        if ( position.y > height ) position.y = -height;
        if ( position.y < -height ) position.y = height;
        if ( position.z > depth ) position.z = -depth;
        if ( position.z < -depth ) position.z = depth;
    }
    
    private function avoid(target:Vector3D):Vector3D {
        var steer:Vector3D = position.clone();
        steer.decrementBy( target );
        steer.scaleBy( 1 / distanceToSquared( position, target ));
        
        return steer;
    }
    
    private function sub(v1:Vector3D, v2:Vector3D):Vector3D {
        var dis:Vector3D = new Vector3D();
        dis.x = v1.x - v2.x;
        dis.y = v1.y - v2.y;
        dis.z = v1.z - v2.z;

        return dis;
    }
    
    private function distanceToSquared(v1:Vector3D, v2:Vector3D):Number {
        var dis:Vector3D = sub(v1, v2);
        var sq:Number = dis.lengthSquared;
        return sq;
    }
    
    public function repulse(target:Vector3D):void {
        var distance:Number = Vector3D.distance(position, target);

        if ( distance < 150 ) {
            var steer:Vector3D = sub( position, target );
            steer.scaleBy( 1 / distance );
            acceleration.incrementBy( steer );
        }
    }
    
    private function reach(target:Vector3D, amount:Number):Vector3D {
        var steer:Vector3D =  sub( target, position );
        steer.scaleBy( amount );
        return steer;
    }
    
    //整列
    private function alignment(boids:Vector.<Boid>):Vector3D {
        var boid:Boid, count:Number = 0;
        var velSum:Vector3D = new Vector3D();
        
        for ( var i:uint = 0; i < boids.length; i++ ) {
            if ( Math.random() > 0.6 ) continue;
            boid = boids[i];
            var distance:Number = Vector3D.distance(boid.position, position);
            
            if ( distance > 0 && distance <= neighborhoodRadius ) {
                velSum.incrementBy( boid.velocity );
                count++;
            }
        }

        if ( count > 0 ) {
            velSum.scaleBy( 1 / count );
            var l:Number = velSum.length;
            if ( l > maxSteerForce ) {
                velSum.scaleBy( 1 / (l / maxSteerForce) );
            }
        }

        return velSum;
    }
    
    //結合
    private function cohesion(boids:Vector.<Boid>):Vector3D {
        var boid:Boid, distance:Number, count:Number = 0;
        var steer:Vector3D = new Vector3D();
        var posSum:Vector3D = new Vector3D();
        
        for ( var i:uint = 0; i < boids.length; i++ ) {
            if ( Math.random() > 0.6 ) continue;
            boid = boids[i];
            distance = Vector3D.distance(boid.position, position);

            if ( distance > 0 && distance <= neighborhoodRadius ) {
                posSum.incrementBy( boid.position );
                count++;
            }
        }
        
        if ( count > 0 ) {
            posSum.scaleBy( 1 / count );
        }

        steer = sub( posSum, position );

        var l:Number = steer.length;
        if ( l > maxSteerForce ) {
            steer.scaleBy( 1 / (l / maxSteerForce) );
        }
        
        return steer;
    }
    
    //引き離し
    private function separation(boids:Vector.<Boid>):Vector3D {
        var boid:Boid, distance:Number, repulse:Vector3D;
        var posSum:Vector3D = new Vector3D();
        
        for ( var i:uint=0; i < boids.length; i++ ) {
            if ( Math.random() > 0.6 ) continue;
            boid = boids[ i ];
            distance = Vector3D.distance(boid.position, position);
            
            if ( distance > 0 && distance <= neighborhoodRadius ) {
                repulse = sub(position, boid.position);
                repulse.normalize();
                repulse.scaleBy( 1 / distance );
                posSum.incrementBy(repulse);
            }
        }

        return posSum;
    }
}



import flash.geom.Matrix3D;
import flash.geom.Vector3D;
import flash.geom.PerspectiveProjection;
class Camera3D extends Matrix3D {
    //3D
    private var perspective:PerspectiveProjection = new PerspectiveProjection();
    private var viewFocus:Number = 10000;
    
    public function Camera3D():void {
        init();
    }
    
    private function init():void {
        perspective.focalLength = viewFocus; //焦点距離
        appendTranslation(0, 0, -10000);
        append(perspective.toMatrix3D());
    }
}


import flash.display.BitmapData;
import flash.display.Sprite;
import flash.geom.Utils3D;

class Object3D extends Sprite {
    private var size:uint = 10;
    
    //2D
    public var world:Sprite = new Sprite(); 
    protected var vertices2D:Vector.<Number> = new Vector.<Number>();
    
    //3D
    public var worldMatrix3D:Matrix3D = new Matrix3D();
    protected var camera3d:Camera3D;
    protected var vertices3D:Vector.<Number>;
    protected var indices:Vector.<int>;
    protected var uvtData:Vector.<Number>;
    
    //Draw
    protected var bmpData:BitmapData;
    
    public function Object3D(camera3d:Camera3D):void {
        this.camera3d = camera3d;
        addChild(this.world);
        init();
    }
    
    private function init():void {
        var sprite:Sprite = new Sprite();
        sprite.graphics.beginFill(0x111);
        sprite.graphics.drawRect(0, 0, 10, 10);
        sprite.graphics.endFill();
        
        bmpData = new BitmapData(size, size, true);
        bmpData.draw(sprite);
        
        vertices3D = new Vector.<Number>();
        indices  = new Vector.<int>();
        uvtData = new Vector.<Number>();
        
        world.x = 250;
        world.y = 250;
        addChild(world);
        
        var nUnit:Number = size / 2;
        
        vertices3D.push(-nUnit, -nUnit, 0);
        vertices3D.push(nUnit, -nUnit, 0);
        vertices3D.push(-nUnit, nUnit, 0);
        vertices3D.push(nUnit, nUnit, 0);
        
        indices.push(0, 1, 2);
        indices.push(1, 3, 2);
        
        uvtData.push(0, 0, 0);
        uvtData.push(1, 0, 0);
        uvtData.push(0, 1, 0);
        uvtData.push(1, 1, 0);
    }
    
    public function update():void {
        //3D処理
        var matrix3D:Matrix3D = worldMatrix3D.clone();
        matrix3D.append(camera3d);
        Utils3D.projectVectors(matrix3D, vertices3D, vertices2D, uvtData);
            
        //描画
        world.graphics.clear();
        world.graphics.beginBitmapFill(bmpData);
        world.graphics.drawTriangles(vertices2D, indices, uvtData);
        world.graphics.endFill();
    }    
}