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

Beat Driven Flocking: forked from: Flock Behavior Test

...
@author Motoki Matsumoto
also look at : http://wonderfl.net/c/lV7u
Get Adobe Flash player
by aobyrne 09 May 2012
/**
 * Copyright aobyrne ( http://wonderfl.net/user/aobyrne )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/cKU8
 */

// forked from mtok's Seek Behavior Test
package  
{
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.DisplayObject;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.filters.BlurFilter;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import flash.media.Sound;
    import flash.media.SoundLoaderContext;
    import flash.media.SoundMixer;
    import flash.net.URLRequest;
    import flash.utils.ByteArray;
    /**
     * ...
     * @author Motoki Matsumoto
     */
    public class FlockBehaviorBeatDriven extends Sprite
    {
        private var flockBehaviour:FlockBehaviour;
        private var sound:Sound;
        private var gui:GUI;
        private var arrayMaxSpeed:Array;
        private var currentBand:String='1';
        private var bitmapData:BitmapData;
        private var rr:Rectangle;
        private var pointOrigin:Point;
        private var container:Sprite;
        private var blurFilter:BlurFilter;
        public var amplitudes:Array;
        public function FlockBehaviorBeatDriven() 
        {
            //var a:DisplayObject = 
            container = addChild(new Sprite) as Sprite;
            container.visible = false;
            bitmapData = new BitmapData(465, 465, true, 0x00ffffff);
            rr = bitmapData.rect;
            pointOrigin = new Point;
            blurFilter = new BlurFilter(1.05, 1.05);
            flockBehaviour =container.addChild(new FlockBehaviour(false,0xff00000,6,23)) as FlockBehaviour;
            var a:DisplayObject = container.addChild(new FlockBehaviour(true, 0xcccccc, 40));
            FlockBehaviour(a).setMaxSpeed(3);
            
            guiCall();
            setChildIndex(container, numChildren -1);
            addChild(new Bitmap(bitmapData));
            addEventListener(Event.ENTER_FRAME, just_once);
        }
        
        
        private function just_once(e:Event):void 
        {
            removeEventListener(Event.ENTER_FRAME, just_once);
            arrayMaxSpeed = [];
            addEventListener(Event.ENTER_FRAME, loop);
            initSound();
            
        }
        
        
        
        private function loop(e:Event):void 
        {
            computeSpectrum();
            var a:Array = amplitudes;
            var a1:Number = a[0];
            var a2:Number = a[1];
            var a3:Number = a[2];
            //currentBand = '';
            var number:Number = Number(a[int(currentBand) - 1]);
            doMaxSpeed(number);
            gui.charts[0].addToArray(a1);
            gui.charts[1].addToArray(a2);
            gui.charts[2].addToArray(a3);
            flockBehaviour.update();
            bitmapData.draw(container);
            bitmapData.applyFilter(bitmapData, rr, pointOrigin, blurFilter);
        }
        
        private function doMaxSpeed(e:Number):void 
        {
            var threshold:Number = 0.2;
            var minimum:Number = 2;
            var factor:Number = 20;
            var number:Number = e > threshold?minimum + (e-threshold) * factor:minimum;
            number = minimum + e * factor;
            gui.maxSpeedhUISlider.value = number;
            flockBehaviour.setMaxSpeed(number);
            //arrayMaxSpeed[arrayMaxSpeed.length] = e;
            //if (arrayMaxSpeed.length>100) 
            //{
                //arrayMaxSpeed.shift();
            //}
            //gui.charts[0].data = arrayMaxSpeed ;
            //gui.charts[0].addToArray(e);
        }
        
        public function computeSpectrum():void 
        {
            var amplitude:Number;
            var soundByteArray:ByteArray = new ByteArray;
            var fftMode:Boolean = true;
            var stretchFactor:int = 0;
            SoundMixer.computeSpectrum(soundByteArray, fftMode, stretchFactor);
            var ranges:Array = [[1, 2, 3], [14, 16, 18], [30, 33, 36]];
            amplitudes = [];
            const theSizeOfAFloatInBytes:int = 4;
            var rl:uint = ranges.length;
            for (var j:int = 0; j < rl; j++) 
            {
                var ar:Array = ranges[j];
                var al:uint = ar.length;
                amplitude = 0;
                for (var k:int = 0; k < al; k++) 
                {
                    var i:uint = ar[k];
                    soundByteArray.position = i * theSizeOfAFloatInBytes;
                    amplitude += soundByteArray.readFloat();
                }
                amplitude /= al;
                amplitudes[j] = amplitude;
            }

        }
        
        public function setBand(label:String):void 
        {
            currentBand = label;
        }
        
    private function initSound() :void {
        var soundPath:String = "http://www.takasumi-nagai.com/soundfiles/sound001.mp3";
        //soundPath = 'assets/realentada.mp3';
        sound = new Sound();
        sound.addEventListener(Event.COMPLETE, function(e :Event) :void {
            start();
        }, false, 0, true);
        sound.load(new URLRequest(soundPath), new SoundLoaderContext(10, true));
    }
    
    private function start():void {
        sound.play(0, 1000);
        //addEventListener(Event.ENTER_FRAME, update, false, 0, true);
    }
    
    private function guiCall():void 
    {
        gui = new GUI(this, flockBehaviour);
        gui.visibility();
        stage.addEventListener(KeyboardEvent.KEY_DOWN, function(e:KeyboardEvent):void { if ("V"== String.fromCharCode(e.keyCode)) gui.visibility(); } );
        
    }
    }
}
import com.bit101.charts.LineChart;
import com.bit101.components.RadioButton;
import flash.display.DisplayObjectContainer;
import flash.display.Graphics;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import com.bit101.components.HBox;
import com.bit101.components.HUISlider;
import com.bit101.components.PushButton;
import com.bit101.components.VBox;
class GUI
{
    private var flockBehaviour:FlockBehaviour;
    private var sprite:Sprite;
    private var vBox:VBox;
    public var charts:Vector.<SCLineChart>;
    public var maxSpeedhUISlider:HUISlider;
    public function GUI(sprite:Sprite, flockBehaviour:FlockBehaviour ) 
    {
        var radioButton:RadioButton;
        this.sprite = sprite;
        this.flockBehaviour = flockBehaviour;
        vBox = new VBox(sprite,10,10);
        var hBox:HBox = new HBox(vBox, 10, 10);
        maxSpeedhUISlider = new HUISlider(hBox, 0, 0, 'maxspeed', onMaxspeed);
        maxSpeedhUISlider.maximum = 20;
        maxSpeedhUISlider.minimum = 1;
        maxSpeedhUISlider.tick = 1;
        maxSpeedhUISlider.value = initMaxspeed_global;
        var inSightDisthUISlider:HUISlider = new HUISlider(hBox, 0, 0, 'in sight', onInsightDistance);
        inSightDisthUISlider.minimum = 50;
        inSightDisthUISlider.maximum = 200;
        inSightDisthUISlider.value = inSightDistanceInit_global;
        //new PushButton(vBox, 0, 0, 'spectrum', onSpectrum);
        charts = Vector.<SCLineChart>([]);
        for (var i:int = 0; i < 3; i++) 
        {
            
        var lineChart:SCLineChart = new SCLineChart(vBox, 0, 0);
        lineChart.data = [];
        lineChart.autoScale = false;
        lineChart.minimum = 0;
        lineChart.maximum = 1;
        charts[i] = lineChart;
        }
        for (var j:int = 0; j < 3; j++) 
        {
            radioButton = new RadioButton(vBox, 0, 0, int(j+1).toString() , false, onRadioButton);
            radioButton.name = int(j+1).toString();
        }
    }
    public function visibility():void 
    {
        vBox.visible = !vBox.visible;
    }
    
    private function onRadioButton(e:Event):void 
    {
        var radioButton:RadioButton = e.target as RadioButton;
        FlockBehaviorBeatDriven(sprite).setBand(radioButton.label)
    }
        private function onSpectrum(e:Event):void 
        {
            FlockBehaviorBeatDriven(sprite).computeSpectrum();
        }
        private function onInsightDistance(e:Event):void 
        {
            flockBehaviour.setInsightDist(HUISlider(e.target).value);
        }
        
        private function onMaxspeed(e:Event):void 
        {
            flockBehaviour.setMaxSpeed(HUISlider(e.target).value);
        }
}

class SCLineChart extends LineChart
{
    private var array1:Array;
    private var oldValue:Number=0;
        public function SCLineChart(parent:DisplayObjectContainer=null, xpos:Number=0, ypos:Number=0, data:Array=null)
        {
            super(parent, xpos, ypos, data);
            array1 = [];
        }
        public function addToArray(value:Number,index:int=-1):void 
        {
            if (index==-1) 
            {
                oldValue = array1.length>1?array1[array1.length - 1]:oldValue;
                value = 0.5*(oldValue + value);
                array1[array1.length]=value
            }
            else
            {
                array1[index] = value;
                
            }
            if (array1.length>100) 
            {
                array1.shift();
            }
            data = array1;
            
        }
        
}



    class FlockBehaviour extends Sprite
    {
        private var _vehicles:Array;
        private var amount:int = 30;
        private var isAutomatic:Boolean;
        private var color:uint;
        private var size:Number;
        
        public function FlockBehaviour(isAutomatic:Boolean = true, color:uint=0, amount:Number=30, size:Number=4) 
        {
            this.size = size;
            this.amount = amount;
            this.color = color;
            this.isAutomatic = isAutomatic;
            addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
        }
        
        private function addedToStageHandler(e:Event):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
            init();
        }
        private function init():void {
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            
            _vehicles = [];
            var v:Vehicle;
            for ( var i:int = 0; i < amount; i++) {
                v = new Vehicle(this.color,this.size);
                //v.edgeBehavior = Vehicle.WRAP;
                v.position = new Vector2D(
                    Math.random() * stage.stageWidth,
                    Math.random() * stage.stageHeight);
                v.velocity = new Vector2D(
                    Math.random() * 20 - 10,
                    Math.random() * 20 - 10);
                    
                v.edgeBehavior = Vehicle.BOUNCE;
                _vehicles.push(v);
                addChild(v);
            }
            
            if(isAutomatic) addEventListener(Event.ENTER_FRAME, enterFrameHandler);

        }
        
        public function setInsightDist(e:Number):void 
        {
            var vl:uint = _vehicles.length;
            while (vl--) 
            {
                Vehicle(_vehicles[vl]).inSightDist = e;
            }
        }
        
        public function setMaxSpeed(e:Number):void 
        {
            var vehicle:Vehicle;
            var vl:uint = _vehicles.length;
            while (vl--) 
            {
                vehicle = _vehicles[vl] as Vehicle;
                vehicle.maxSpeed = e;
            }
        }
        public function update():void 
        {
            enterFrameHandler(null);
        }        
        private function enterFrameHandler(e:Event):void 
        {
            
            for (var i:int = 0; i < _vehicles.length; i++) {
                _vehicles[i].flock(_vehicles);
                _vehicles[i].update();
            }
        }
    }

class Vector2D {
    private var _x:Number;
    private var _y:Number;
    public function Vector2D(x:Number = 0, y:Number = 0) {
        _x = x;
        _y = y;
    }
    
    /**
     * draw 
     */
    public function draw(graphics:Graphics, color:uint):void {
        graphics.lineStyle(0, color);
        graphics.moveTo(0, 0);
        graphics.lineTo(_x, _y);
    }
    public function get x():Number { return _x; }
    public function set x(value:Number):void 
    {
        _x = value;
    }
    
    public function get y():Number { return _y; }
    public function set y(value:Number):void 
    {
        _y = value;
    }
    
    /**
     * 複製する
     * @return
     */
    public function clone():Vector2D {
        return new Vector2D(_x, _y);
    }
    /**
     * ベクトルをゼロに
     * @return
     */
    public function zero():Vector2D {
        _x = _y = 0;
        return this;
    }
    
    /**
     * ベクトルがゼロか?
     * @return
     */
    public function isZero():Boolean {
        return _x == 0 && _y == 0;
    }
    
    /**
     * ベクトルの大きさを指定したサイズに
     */
    public function set length(value:Number):void {
        var a:Number = angle;
        _x = Math.cos(a) * value;
        _y = Math.sin(a) * value;
    }
    
    /**
     * ベクトルの長さ
     */
    public function get length():Number {
        return Math.sqrt(lengthSQ);
    }
    
    /**
     * ベクトルの長さの2乗
     */
    public function get lengthSQ():Number {
        return _x * _x + _y * _y;
    }
    
    public function get angle():Number {
        return  Math.atan2(_y, _x);
    }
    
    public function set angle(value:Number):void 
    {
        var len:Number = length;
        _x = Math.cos(value) * len;
        _y = Math.sin(value) * len;
    }
    
    
    /**
     * ベクトルを正規化する
     * ベクトルが0の場合、結果を(1,0)とする
     * @return
     */
    public function normalize():Vector2D {
        if (length == 0) {
            _x = 1;
        }else {
            var len:Number = length;        
            _x /= len;
            _y /= len;
            
        }
        return this;
    }
    /**
     * ベクトルの大きさをmaxまでにカットする。
     * @param    max
     * @return
     */
    public function truncate(max:Number):Vector2D {
        var len:Number = length;
        if (len > max) {
            length = max;
        }
        return this;
    }
    /**
     * ベクトルの向きを逆に
     * @return
     */
    public function reverse():Vector2D {
        _x = -_x;
        _y = -_y;
        return this;
    }
    /**
     * ベクトルが正規化されているか?
     * @return
     */
    public function isNormalized():Boolean {
        return length == 1.0;
    }
    
    /**
     * ベクトル Vとの内積を求める
     * @param    v
     * @return
     */
    public function dotProduct(v:Vector2D):Number {
        return _x * v._x + _y * v._y;
    }
    
    /**
     * 内積からベクトルのなす角を求める -PI/2 ~ PI/2
     * @param    v1
     * @param    v2
     * @return
     */
    public static function angleBetween(v1:Vector2D, v2:Vector2D):Number {
        if (!v1.isNormalized()) v1 = v1.clone().normalize();
        if (!v2.isNormalized()) v2 = v2.clone().normalize();
        
        return Math.acos(v1.dotProduct(v2));
    }
    /**
     * ベクトルvが右にあるか左にあるか、
     * @param    v
     * @return
     */
    public function sign(v:Vector2D):int {
        return this.perp.dotProduct(v) < 0 ? -1 : 1;
    }
    
    /**
     * 直交するベクトル
     */
    public function get perp():Vector2D {
        return new Vector2D( -y, x);
    }
    
    public function distance(v:Vector2D):Number {
        return Math.sqrt(distanceSQ(v));
    }
    public function distanceSQ(v:Vector2D):Number {
        var dx:Number = v._x - _x;
        var dy:Number = v._y - _y;
        return dx * dx + dy * dy;
    }
    
    public function add(v:Vector2D):Vector2D {
        return new Vector2D(_x + v._x, _y + v._y);
    }
    public function subtract(v:Vector2D):Vector2D {
        return new Vector2D(_x - v._x, _y - v._y);
    }
    
    public function multiply(value:Number):Vector2D {
        return new Vector2D(_x * value, _y * value);
    }
    
    public function divide(value:Number):Vector2D{
        if (value == 0) {}//後で考える
        return new Vector2D(_x / value, _y / value);
    }
    
    public function equals(v:Vector2D):Boolean {
        return _x == v._x && _y == v._y;
    }
    
    public function toString():String {
        return "[Vector2D( x:" + _x + ", y:" + _y + ", )]";
    }
}

class Vehicle extends Sprite {
    protected var _mass:Number = 1.0;
    protected var _maxSpeed:Number = initMaxspeed_global;
    protected var _position:Vector2D;
    protected var _velocity:Vector2D;
    
    private var _edgeBehavior:Function;
    
    public static const WRAP:String = "wrap";
    public static const BOUNCE:String = "bounce";
    
    private var _maxForce:Number = 1;
    private var _steeringForce:Vector2D;
    private var _arrivalThreshold:Number = 100;
    private var _wanderAngle:Number = 0;
    private var _wanderDistance:Number = 3;
    private var _wanderRadius:Number = 10;
    private var _wanderRange:Number = 3;

    private var _avoidDistance:Number = 100;
    private var _avoidBuffer:Number = 10;

    private var _pathIndex:int = 0;
    private var _pathThreshold:Number = 20;
    private var _tooCloseDist:Number = 30;
    private var _inSightDist:Number = inSightDistanceInit_global;
    private var color:uint;
    private var radius:Number;
    
    public function Vehicle(color:uint=0,radius:Number=4) {
        this.radius = radius;
        this.color = color;
        _steeringForce = new Vector2D();

        _position = new Vector2D();
        _velocity = new Vector2D();
        _edgeBehavior = wrap;
        draw();
        
    }
    
    protected function draw():void
    {
        var g:Graphics = graphics;
        //g.clear();
        //g.lineStyle(0);
        //g.moveTo(10, 0);
        //g.lineTo( -10, 5);
        //g.lineTo( -10, -5);
        //g.lineTo(10, 0);
        g.clear();
        g.lineStyle(0);
        g.beginFill(this.color);
        g.drawCircle(0, 0, radius);
    }
    public function update():void {
        _steeringForce.truncate(maxForce);
        _steeringForce = _steeringForce.divide(_mass);
        _velocity = _velocity.add(_steeringForce);
        
        _velocity.truncate(_maxSpeed);
        
        _steeringForce.x = _steeringForce.y = 0;
        _position = _position.add(_velocity);
        
        _edgeBehavior();
        x = position.x;
        y = position.y;
        
        rotation = _velocity.angle * 180 / Math.PI;
    }
    /**
     * 跳ね返る
     */
    private function bounce():void {
        if (stage != null) {
            var w:Number = stage.stageWidth;
            var h:Number = stage.stageHeight;
            
            if (position.x > w) {
                position.x = w;
                _velocity.x *= -1;
            }else if(position.x < 0){
                position.x = 0;
                _velocity.x *= -1;
            }
            
            if (position.y > h) {
                position.y = h;
                _velocity.y *= -1;
            }else if (position.y < 0) {
                position.y = 0
                _velocity.y *= -1;
            }
        }
    }
    /**
     * 反対側に移動する。
     */
    private function wrap():void {
        if (stage != null) {
            var w:Number = stage.stageWidth;
            var h:Number = stage.stageHeight;
            
            if (position.x > w) position.x = 0;
            if (position.x < 0) position.x = w;
            if ( position.y > h) position.y = 0;
            if ( position.y < 0) position.y = h;
            
        }
    }
    public function get edgeBehavior():String{
        if ( _edgeBehavior == bounce) return Vehicle.BOUNCE;
        if (_edgeBehavior == wrap) return Vehicle.WRAP;
        return "";
    }
    public function set edgeBehavior(value:String):void{
        switch(value) {
        case Vehicle.BOUNCE:
            _edgeBehavior = bounce;
            break;
        case Vehicle.WRAP:
        default:
            _edgeBehavior = wrap;
            break;
        }        
    }
    public function get mass():Number { return _mass; }
    public function set mass(value:Number):void 
    {
        _mass = value;
    }
    
    public function get maxSpeed():Number { return _maxSpeed; }
    public function set maxSpeed(value:Number):void 
    {
        _maxSpeed = value;
    }
    
    public function get position():Vector2D { return _position; }
    public function set position(value:Vector2D):void 
    {
        _position = value;
        x = _position.x;
        y = _position.y;
    }
    
    public function get velocity():Vector2D { return _velocity; }
    public function set velocity(value:Vector2D):void 
    {
        _velocity = value;
    }
    
    override public function set x(value:Number):void 
    {
        super.x = value;
        _position.x = value;
    }
    
    override public function set y(value:Number):void 
    {
        super.y = value;
        _position.y = value;
    }
    
    public function get maxForce():Number { return _maxForce; }
    
    public function set maxForce(value:Number):void 
    {
        _maxForce = value;
    }
    
    public function get pathIndex():int { return _pathIndex; }
    
    public function set pathIndex(value:int):void 
    {
        _pathIndex = value;
    }
    
    public function get pathThreshold():Number { return _pathThreshold; }
    
    public function set pathThreshold(value:Number):void 
    {
        _pathThreshold = value;
    }
    
    public function get inSightDist():Number { return _inSightDist; }
    public function set inSightDist(value:Number):void 
    {
        _inSightDist = value;
    }
    
    public function get tooCloseDist():Number { return _tooCloseDist; }
    public function set tooCloseDist(value:Number):void 
    {
        _tooCloseDist = value;
    }
    
    /**
     * Seek behavior
     * @param    target
     */
    public function seek(target:Vector2D):void {
        var desiredVelocity:Vector2D = target.subtract(_position);
        desiredVelocity.normalize();
        desiredVelocity = desiredVelocity.multiply(_maxSpeed);
        var force:Vector2D = desiredVelocity.subtract(_velocity);
        
        _steeringForce = _steeringForce.add(force);
    }
    
    public function flee(target:Vector2D):void {
        var desiredVelocity:Vector2D = target.subtract(_position);
        desiredVelocity.normalize();
        desiredVelocity = desiredVelocity.multiply(_maxSpeed);
        var force:Vector2D = desiredVelocity.subtract(_velocity);
        
        _steeringForce = _steeringForce.subtract(force);        
    }
    public function arrive(target:Vector2D):void {
        var desiredVelocity:Vector2D = target.subtract(_position);
        desiredVelocity.normalize();
        
        
        var dist:Number = _position.distance(target);
        if (dist > _arrivalThreshold) {
            desiredVelocity = desiredVelocity.multiply(_maxSpeed);
        }else {
            //_arrivalThresholdまで近づいたらスピードダウン
            desiredVelocity = desiredVelocity.multiply(_maxSpeed * dist / _arrivalThreshold);
        }
        var force:Vector2D = desiredVelocity.subtract(_velocity);
        _steeringForce = _steeringForce.add(force);
    }
    
    public function pursue(target:Vehicle):void {
        //現在位置からターゲットまでかかる時間
        var lookAheadTime:Number = position.distance(target.position) / _maxSpeed;
        
        var predictedTarget:Vector2D = target.position.add(target.velocity.multiply(lookAheadTime));
        seek(predictedTarget);
    }
    
    public function evade(target:Vehicle):void {
        //現在位置からターゲットまでかかる時間
        var lookAheadTime:Number = position.distance(target.position) / _maxSpeed;
        
        var predictedTarget:Vector2D = target.position.subtract(target.velocity.multiply(lookAheadTime));
        flee(predictedTarget);
    }
    public function wander():void {
        //進行方向から_wanderDistance進んだ位置をcenter
        var center:Vector2D = velocity.clone().normalize().multiply(_wanderDistance);
        
        //centerからのずれ
        var offset:Vector2D = new Vector2D(0,0);
        offset.length = _wanderRadius;
        offset.angle = _wanderAngle;
        _wanderAngle += Math.random() * _wanderRange - _wanderRange * 0.5;
        
        var force:Vector2D = center.add(offset);
        _steeringForce = _steeringForce.add(force);
    }
    
    public function avoid(circles:Array):void {
        var i:int;
        var len:int = circles.length;
        var c:Circle;
        var heading:Vector2D;
        var feeler:Vector2D;
        var projection:Vector2D;
        var dist:Number;
        var force:Vector2D;
        
        for (i = 0; i < len; i++) {
            heading = _velocity.clone().normalize();
            c = circles[i] as Circle;
            
            var difference:Vector2D = c.position.subtract(_position);
            var dotProd:Number = difference.dotProduct(heading);
            
            //進行方向前方にCircleがあるか?
            if (dotProd > 0) {
                feeler = heading.multiply(_avoidDistance);
                projection = heading.multiply(dotProd);
                dist = projection.subtract(difference).length;
                
                //衝突するか?
                if (dist < c.radius + _avoidBuffer && projection.length < feeler.length) {
                    force = heading.multiply(_maxSpeed);
                    force.angle += difference.sign(_velocity) * Math.PI / 2;
                    
                    force = force.multiply(1.0 - projection.length / feeler.length);
                    
                    _steeringForce  = _steeringForce.add(force);
                    
                    //スピードを落とす
                    _velocity = _velocity.multiply(projection.length / feeler.length);
                }
                
            }
        }
    }
    public function followPath(path:Array, loop:Boolean = false):void {
        var wayPoint:Vector2D = path[_pathIndex] as Vector2D;
        if (wayPoint == null) return;
        
        if (_position.distance(wayPoint) < _pathThreshold) {
            if (_pathIndex >= path.length - 1) {
                if (loop) {
                    _pathIndex = 0;
                }
            }else {
                _pathIndex++;
            }
        }
        if (_pathIndex >= path.length - 1 && !loop) {
            arrive(wayPoint);
        }else {
            seek(wayPoint);
        }
    }
    
    /**
     * flocking
     * @param    vehicles
     */
    public function flock(vehicles:Array):void {
        var averageVelocity:Vector2D = _velocity.clone();
        var averagePosition:Vector2D = new Vector2D();
        var inSightCount:int = 0;
        
        var len:int = vehicles.length;
        var v:Vehicle;
        
        /*
         * inSightの範囲にある他のVehicleの平均位置と速度を求める。
         * 近づきすぎている場合は、fleeする。
         */
        for (var i:int = 0; i < len; i++) {
            v = vehicles[i] as Vehicle;
            if (v != this && inSight(v)) {
                averageVelocity = averageVelocity.add(v.velocity);
                averagePosition = averagePosition.add(v.position);
                
                if (tooClose(v)) {
                    flee(v.position);
                }
                
                inSightCount++;
            }
        }
        if (inSightCount > 0) {
            averagePosition = averagePosition.divide(inSightCount);
            averageVelocity = averageVelocity.divide(inSightCount);
            
            //求めた平均位置に向かって移動する。
            seek(averagePosition);
            
            //速度を求めた平均速度へと変化させる方向に力を加える
            _steeringForce.add(averageVelocity.subtract(_velocity));
        }
    }
    public function tooClose(vehicle:Vehicle):Boolean {
        return _position.distance(vehicle.position) < _tooCloseDist;
    }
    public function inSight(vehicle:Vehicle):Boolean {
        if (_position.distance(vehicle.position) > _inSightDist) {
            return false;
        }
        var heading:Vector2D = _velocity.clone().normalize();
        var difference:Vector2D = vehicle.position.subtract(_position);
        var dotProd:Number = difference.dotProduct(heading);
        if (dotProd < 0) return false;
        return true;
    }
    
}
class Circle extends Sprite {
    private var _radius:Number;
    private var _color:uint;
    public function Circle(radius:Number, color:uint = 0x000000) {
        _radius = radius;
        _color = color;
        graphics.lineStyle(0, _color);
        graphics.drawCircle(0, 0, _radius);
    }
    
    public function get radius():Number { return _radius; }
    public function set radius(value:Number):void 
    {
        _radius = value;
    }
    public function get position():Vector2D {
        return new Vector2D(x, y);
    }
}
var initMaxspeed_global:Number = 10;
var inSightDistanceInit_global:Number = 200;