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: forked from: forked from: 流体パーティクル(解読用)

mashed:
http://wonderfl.net/c/ubO1
and
Forked (that is http://wonderfl.net/c/jHkD )
// forked from simplychaos's forked from: forked from: 流体パーティクル(解読用)
// forked from tepe's forked from: 流体パーティクル(解読用)
// forked from clockmaker's 流体パーティクル(解読用)
// forked from miniapp's 流体パーティクル
package {
    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;
    import net.hires.debug.Stats;
    
    [SWF(backgroundColor=0x000000, width=465, height=465, frameRate=60)]
    public class FluidLine extends Sprite {
        
        public function FluidLine() {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private var pmouseX:Number;
        private var pmouseY:Number;
        private var canvasWidth:int = 365;
        private var canvasHeight:int = 365;
        private var mousePressed:Boolean;
        private var resolution:int = 15;//グリッドサイズ
        private var penSize:int = 40;
        //グリッド マトリクス
        private var numCols:int = canvasWidth / resolution;//x方向
        private var numRows:int = canvasHeight / resolution;//y方向
        //パーティクル総数
        private var numParticles:int = 15000;
        //グリッドデータ
        private var gridDatasVectors:Vector.<Vector.<GridData>> = new Vector.<Vector.<GridData>>();
        //パーティクルデータ
        private var particles:Vector.<Particle> = new Vector.<Particle>(numParticles, true);
        private var pcount:int = 0;
        private var arrows:Array = [];
//----init----
        private function init(e:Event = null):void {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;
            opaqueBackground = 0x0;
   
            wanderingTarget =          new WanderingTarget;
            wanderingTarget.position = new Vector3D(canvasHeight * 0.5,canvasHeight * 0.5);
            wanderingTarget.boundsCentre = new Vector3D(canvasHeight*0.5, canvasWidth*0.5, 0);
            wanderingTarget.boundsRadius = canvasHeight*0.5;
            //マウスイベント
            //stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
            //stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
            mousePressed = true;
            stage.quality = StageQuality.LOW;
            //addChild(new Stats());
            
            //パーティクル生成
            for (var i:int = 0; i < numParticles; i++) {
                particles[i] = new Particle(Math.random() * canvasWidth, Math.random() * canvasHeight);
            }
            
            //グリッド生成
            for (var col:int=0; col < numCols; ++col) { 
                gridDatasVectors[col] = new Vector.<GridData>(numRows, true);
                arrows[col] = [];
                for (var row:int = 0; row < numRows; ++row) { 
                    var gridData:GridData = new GridData(col * resolution, row * resolution, resolution);
                    gridData.col = col;
                    gridData.row = row;
                    gridDatasVectors[col][row] = gridData;
                    
                    var arrow:Arrow = new Arrow();
                    addChild(arrow);
                    arrows[col][row] = arrow;
                }
            }
            
            //グリッド描画
            var gridView:Shape = new Shape();
            gridView.graphics.beginFill(0x808080);
            addChild(gridView);
            for (col = 0; col <= numCols; ++col) {
                gridView.graphics.drawRect(0, col * resolution, canvasWidth, 1);
            }
            for (row = 0; row <= numRows; ++row) { 
                gridView.graphics.drawRect(row * resolution, 0, 1, canvasHeight);
            }
            
            //隣接するグリッドをセットしていく。
            for (col = 0; col < numCols; ++col) { //col:X方向
                for (row = 0; row < numRows; ++row) { //row:Y方向
                    gridData = gridDatasVectors[col][row];
                    if (row > 0) {
                        var up:GridData = gridDatasVectors[col][row - 1];//上
                        gridData.up = up;
                        up.low = gridData;//下
                    }
                    
                    if (col > 0) {
                        var left:GridData = gridDatasVectors[col - 1][row];//左
                        gridData.left = left;
                        left.right = gridData;//右
                    }
                    
                    if (row > 0 && col > 0) {
                        var upperLeft:GridData = gridDatasVectors[col - 1][row - 1];
                        gridData.upperLeft = upperLeft;
                        upperLeft.lowerRight = gridData;
                    }
                    
                    if (row > 0 && col < numCols - 1) {
                        var upperRight:GridData = gridDatasVectors[col + 1][row - 1];
                        gridData.upperRight = upperRight;
                        upperRight.lowerLeft = gridData;
                    }
                }
            }
            
            gridDatasVectors.fixed = true;
            addEventListener(Event.ENTER_FRAME, draw);//フレーム処理
        }
//----init----

//--------        
        private function mouseDownHandler(e:Event):void {
            mousePressed = true;
        }
        
        private function mouseUpHandler(e:Event):void {
            mousePressed = false;
        }
//--------
//----draw----        
        private function draw(e:Event):void {
            wanderingTarget.wander();
            wanderingTarget.update();
            var mouseXvel:Number = wanderingTarget.x - pmouseX;
            var mouseYvel:Number = wanderingTarget.y - pmouseY;
            
            for each(var gridDatas:Vector.<GridData> in gridDatasVectors) {
                for each(var gridData:GridData in gridDatas) {
                    if (mousePressed) {//マウスドラッグ操作
                        updateGridDataVelocity(gridData, mouseXvel, mouseYvel, penSize);
                    }
                    updatePressure(gridData);
                    
                }
            }
            
            graphics.clear();
            graphics.lineStyle(1, 0xFFFFFF);
            updateParticle();
            
            for each(gridDatas in gridDatasVectors) {
                for each(gridData in gridDatas) {
                    apdateVelocity(gridData);
                }
            }
            
            pmouseX = wanderingTarget.x;
            pmouseY = wanderingTarget.y;
        }
//----draw----
//----updateParticle----
        public function updateParticle():void {
            for each(var p:Particle in particles) {
                if (p.x >= 0 && p.x < canvasWidth && p.y >= 0 && p.y < canvasHeight) {
                    var col:int = int(p.x / resolution);//自身が属しているgridDataを見つける
                    var row:int = int(p.y / resolution);
                    
                    if (col > numCols - 1) col = numCols - 1;
                    if (row > numRows - 1) row = numRows - 1;
                    
                    var gridData:GridData = gridDatasVectors[col][row];
                    
                    var ax:Number = (p.x % resolution) / resolution;
                    var ay:Number = (p.y % resolution) / resolution;
                    p.xvel += (1 - ax) * gridData.xvel * 0.05;
                    p.yvel += (1 - ay) * gridData.yvel * 0.05;
                    
                    p.xvel += ax * gridData.right.xvel * 0.05;
                    p.yvel += ax * gridData.right.yvel * 0.05;
                    
                    p.xvel += ay * gridData.low.xvel * 0.05;
                    p.yvel += ay * gridData.low.yvel * 0.05;
                    
                    p.x += p.xvel;
                    p.y += p.yvel;
                    
                    var dx:Number = p.px - p.x;
                    var dy:Number = p.py - p.y;
                    var dist:Number = Math.sqrt(dx * dx + dy * dy);
                    var limit:Number = Math.random() * 0.5;
                    
                    if (dist > limit) {
                        graphics.moveTo(p.x, p.y);
                        graphics.lineTo(p.px, p.py);
                    }
                    else {
                        graphics.moveTo(p.x, p.y);
                        graphics.lineTo(p.x + limit, p.y + limit);
                    }
                    
                    p.px = p.x;
                    p.py = p.y;
                }
                else {
                    p.x = p.px = Math.random() * canvasWidth;
                    p.y = p.py = Math.random() * canvasHeight;
                    p.xvel = 0;
                    p.yvel = 0;
                }
                
                p.xvel *= 0.5;
                p.yvel *= 0.5;
            }
        }
//----updateParticle----
//----updateGridDataVelocity----
        /**
         * マウスドラッグの処理
         * @param    gridData
         * @param    mvelX
         * @param    mvelY
         * @param    penSize
         */
        public function updateGridDataVelocity(gridData:GridData,//更新するグリッド
                                            mvelX:int, mvelY:int,//マウス移動量
                                            penSize:Number):void {//ペン
            var dx:Number = gridData.x - wanderingTarget.x;
            var dy:Number = gridData.y - wanderingTarget.y;
            var dist:Number = Math.sqrt(dy * dy + dx * dx);
            
            if (dist < penSize) { 
                if (dist < 4) {
                    dist = penSize;
                }
                
                //マウスに近いほど力が強くなるように。
                var power:Number = penSize / dist;
                gridData.xvel += mvelX * power;
                gridData.yvel += mvelY * power;
            }
        }
//----updateGridDataVelocity----
//----updatePressure----
        private var n1:Number = 0.1;//周囲のグリッドへの影響
        private var n2:Number = 0.1;//減衰量
        private var wanderingTarget:WanderingTarget;
        public function updatePressure(gridData:GridData):void {
            var pressureX:Number = (
                  gridData.upperLeft.xvel * n1 //左上
                + gridData.left.xvel       //左
                + gridData.lowerLeft.xvel * n1 //左下
                - gridData.upperRight.xvel * n1 //右上
                - gridData.right.xvel       //右
                - gridData.lowerRight.xvel * n1 //右下
            );
            
            var pressureY:Number = (
                  gridData.upperLeft.yvel * n1 //左上
                + gridData.up.yvel       //上
                + gridData.upperRight.yvel * n1 //右上
                - gridData.lowerLeft.yvel * n1 //左下
                - gridData.low.yvel       //下
                - gridData.lowerRight.yvel * n1 //右下
            );
            
            gridData.pressure = (pressureX + pressureY) * n2;
            
            //ベクトル表示
            var arrow:Arrow = arrows[gridData.col][gridData.row];
            arrow.x = gridData.x + resolution / 2 >> 0;
            arrow.y = gridData.y + resolution / 2 >> 0;
            arrow.rotation = Math.atan2(gridData.yvel, gridData.xvel) * 180 / Math.PI;
            arrow.scaleX = arrow.scaleY = Math.sqrt(gridData.yvel * gridData.yvel + gridData.xvel * gridData.xvel) / 100
            
        }
//----updatePressure----
//----apdateVelocity----        
        public function apdateVelocity(gridData:GridData):void {
            gridData.xvel += (
                  gridData.upperLeft.pressure * 0.5 //左上
                + gridData.left.pressure       //左
                + gridData.lowerLeft.pressure * 0.5 //左下
                - gridData.upperRight.pressure * 0.5 //右上
                - gridData.right.pressure       //右
                - gridData.lowerRight.pressure * 0.5 //右下
            ) * 0.25;
            
            gridData.yvel += (
                  gridData.upperLeft.pressure * 0.5 //左上
                + gridData.up.pressure       //上
                + gridData.upperRight.pressure * 0.5 //右上
                - gridData.lowerLeft.pressure * 0.5 //左下
                - gridData.low.pressure       //下
                - gridData.lowerRight.pressure * 0.5 //右下
            ) * 0.25;
            
            gridData.xvel *= 0.99;
            gridData.yvel *= 0.99;
        }
//----apdateVelocity----

    }    
}//---Main---

//----------------------------
// >>> GridData
import flash.geom.Rectangle;
class BaseGridData {
    
    public var col:int = 0;
    public var row:int = 0;
    
    public var x:int = 0;
    public var y:int = 0;
    
    public var xvel:Number = 0;
    public var yvel:Number = 0;
    
    public var pressure:Number = 0;
    
    public var color:Number = 0;
    public var rgb:uint;
    public var rectangle:Rectangle;
}
//----------------------------

class GridData extends BaseGridData{
    
    public function GridData(x:int, y:int, resolution:Number) {
        this.x = x;
        this.y = y;
        rectangle = new Rectangle(x, y, resolution, resolution)
    }
    
    //すべてのグリッドが8方向に隣接したグリッドを持つわけではないので、
    //空のデータをセットしておく。
    public var upperLeft:BaseGridData = new NullGridData();//左上
    public var up:BaseGridData = new NullGridData();//上
    public var upperRight:BaseGridData = new NullGridData();//右上
    
    public var left:BaseGridData = new NullGridData();//左
    public var right:BaseGridData = new NullGridData();//右
    
    public var lowerLeft:BaseGridData = new NullGridData();//左下
    public var low:BaseGridData = new NullGridData();//下
    public var lowerRight:BaseGridData = new NullGridData();//右下    
}

//----------------------------
// >>> GridData
class NullGridData extends BaseGridData{
}

//----------------------------

class Particle {    
    
    public function Particle(x:Number, y:Number) {
        this.x = px = x;
        this.y = py = y;
    }
    
    public var x:Number;
    public var y:Number;
    
    public var px:Number;
    public var py:Number;
    public var xvel:Number = 0;
    public var yvel:Number = 0;
    
}

//----------------------------

import flash.display.*;
class Arrow extends Sprite
{
    function Arrow() {
        var s:Shape = new Shape();
        s.graphics.beginFill(0xFF0000, 1);
        s.graphics.moveTo(2, 4);
        s.graphics.lineTo(8, 4);
        s.graphics.lineTo(8, 0);
        s.graphics.lineTo(20, 7);
        s.graphics.lineTo(8, 14);
        s.graphics.lineTo(8, 10);
        s.graphics.lineTo(2, 10);
        s.graphics.lineTo(2, 4);
        
        s.x = -10;
        s.y = -7;
        addChild(s);
    }
}
import flash.display.DisplayObject;
import flash.geom.Matrix3D;
import flash.geom.Point;
import flash.geom.Vector3D;

import org.papervision3d.cameras.Camera3D;
import org.papervision3d.objects.DisplayObject3D;

internal class WanderingTarget extends Point
{
    /** 
     * SEE http://blog.soulwire.co.uk/laboratory/flash/as3-flocking-steering-behaviors
     * SOUL WIRE
     */
    private var _matrix : Matrix3D;
    private var _maxForce : Number;
    private var _maxSpeed : Number;
    private var _distance : Number;
    private var _drawScale : Number;
    private var _maxForceSQ : Number;
    private var _maxSpeedSQ : Number;
    private var _velocity : Vector3D;
    private var _position : Vector3D;
    private var _oldPosition : Vector3D;
    private var _acceleration : Vector3D;
    private var _steeringForce : Vector3D;
    private var _screenCoords : Point;
    private var _renderData : DisplayObject;
    private var _edgeBehavior : String;
    private var _boundsRadius : Number;
    private var _boundsCentre : Vector3D = new Vector3D();
    private var _radius : Number = 10.0;
    private var _wanderTheta : Number = 0.0;
    private var _wanderRadius : Number = 16.0;
    private var _wanderDistance : Number = 60.0;
    private var _wanderStep : Number = 0.25;
    private var _lookAtTarget : Boolean = true;
    
    protected var _config : Object = {
        minForce:3.0,
        maxForce:6.0,
        minSpeed:6.0,
        maxSpeed:12.0,
        minWanderDistance:10.0,
        maxWanderDistance:100.0,
        minWanderRadius:5.0,
        maxWanderRadius:20.0,
        minWanderStep:0.1,
        maxWanderStep:0.9,
        boundsRadius:250,
        numBoids:120
    };
    
    public function WanderingTarget()
    {
        maxForce = 2;//random(_config.minForce, _config.maxForce);
        maxSpeed = 7;//;random(_config.minSpeed, _config.maxSpeed);
        _wanderDistance = 15;//random(_config.minWanderDistance, _config.maxWanderDistance);
        _wanderRadius = 5;//random(_config.minWanderRadius, _config.maxWanderRadius);
        _wanderStep = 0.5;//random(_config.minWanderStep, _config.maxWanderStep);
        
        super();
        reset();
        //super(fov, near, far, useCulling, useProjection);
    }
    
    /**
     * Generates a random wandering force for the Boid. 
     * The results of this method can be controlled by the 
     * _wanderDistance, _wanderStep and _wanderRadius parameters
     * 
     * @param    multiplier
     * 
     * By multiplying the force generated by this behavior, 
     * more or less weight can be given to this behavior in
     * comparison to other behaviors being calculated by the 
     * Boid. To increase the weighting of this behavior, use 
     * a number above 1.0, or to decrease it use a number 
     * below 1.0
     */
    
    public function wander( multiplier : Number = 1.0 ) : void
    {
        _wanderTheta += Math.random() * _wanderStep;
        
        if ( Math.random() < 0.5 )
        {
            _wanderTheta = -_wanderTheta;
        }
        
        var pos : Vector3D = _velocity.clone();
        
        //trace(pos)
        
        pos.normalize();
        pos.scaleBy(_wanderDistance);
        pos.incrementBy(_position);
        
        var offset : Vector3D = new Vector3D();
        
        offset.x = _wanderRadius * Math.cos(_wanderTheta);
        offset.y = _wanderRadius * Math.sin(_wanderTheta);
        //offset.z = _wanderRadius * Math.tan(_wanderTheta);
        //    trace(offset)
        //trace(_wanderRadius, _wanderTheta, pos, offset)
        _steeringForce = steer(pos.add(offset));
        
        if ( multiplier != 1.0 )
        {
            _steeringForce.scaleBy(multiplier);
        }
        //    trace(_steeringForce)
        
        _acceleration.incrementBy(_steeringForce);
    }
    
    private function steer( target : Vector3D, ease : Boolean = false, easeDistance : Number = 100 ) : Vector3D
    {
        //trace(_steeringForce,target.clone());
        
        _steeringForce = target.clone();
        _steeringForce.decrementBy(_position);
        //trace(_steeringForce,target.clone());
        _distance = _steeringForce.normalize();
        //trace('ab', _distance)
        
        if ( _distance > 0.00001 )
        {
            if ( _distance < easeDistance && ease )
            {
                _steeringForce.scaleBy(_maxSpeed * ( _distance / easeDistance ));
            }
            else
            {
                _steeringForce.scaleBy(_maxSpeed);
            }
            
            _steeringForce.decrementBy(_velocity);
            
            if ( _steeringForce.lengthSquared > _maxForceSQ )
            {
                _steeringForce.normalize();
                _steeringForce.scaleBy(_maxForce);
            }
        }
        //trace(_steeringForce)
        
        return _steeringForce;
    }
    
    public function update() : void
    {
        _oldPosition.x = _position.x;
        _oldPosition.y = _position.y;
        _oldPosition.z = _position.z;
        
        _velocity.incrementBy(_acceleration);
        
        if ( _velocity.lengthSquared > _maxSpeedSQ )
        {
            _velocity.normalize();
            _velocity.scaleBy(_maxSpeed);
        }
        
        _position.incrementBy(_velocity);
        
        x = _position.x;
        y = _position.y;
        //z = _position.z;
        
        
        _acceleration.x = 0;
        _acceleration.y = 0;
        _acceleration.z = 0;
        
        if ( isNaN(_boundsRadius) )
        {
            trace( "isNaN(_boundsRadius) : " + isNaN(_boundsRadius) );
            return;
        }
        
        if( !_position.equals(_oldPosition) )
        {
            var distance : Number = Vector3D.distance(_position, _boundsCentre);
            
            if( distance > _boundsRadius + _radius )
            {
                    
                /**
                 * Move the boid to the edge of the boundary 
                 * then invert it's velocity and step it 
                 * forward back into the sphere 
                 */
                
                _position.decrementBy(_boundsCentre);
                _position.normalize();
                _position.scaleBy(_boundsRadius + _radius);
                
                _velocity.scaleBy(-1);
                _position.incrementBy(_velocity);
                _position.incrementBy(_boundsCentre);
                    
            }
        }
    }
    
    /**
     * Resets the Boid's position, velocity, acceleration and 
     * current steering force to zero
     */
    
    public function reset() : void
    {
        _velocity = new Vector3D();
        _position = new Vector3D();
        _oldPosition = new Vector3D();
        _acceleration = new Vector3D();
        _steeringForce = new Vector3D();
        _screenCoords = new Point();
    }
    
    /**
     * The maximum force available to the Boid when
     * calculating the steering force produced by 
     * the Boids steering bahaviors
     */
    
    public function get maxForce() : Number
    {
        return _maxForce;
    }
    
    public function set maxForce( value : Number ) : void
    {
        if ( value < 0 )
        {
            value = 0;
        }
        
        _maxForce = value;
        _maxForceSQ = value * value;
    }
    
    /**
     * The maximum speed the Boid can reach
     */
    
    public function get maxSpeed() : Number
    {
        return _maxSpeed;
    }
    
    public function set maxSpeed( value : Number ) : void
    {
        if ( value < 0 )
        {
            value = 0;
        }
        
        _maxSpeed = value;
        _maxSpeedSQ = value * value;
    }
    
    protected function random( min : Number, max : Number = NaN ) : Number
    {
        if ( isNaN(max) )
        {
            max = min;
            min = 0;
        }
        
        return Math.random() * ( max - min ) + min;
    }
    
    /**
     * The centrepoint of the Boids bounding sphere.
     * If the Boid travels futher than boundsRadius 
     * from this point the specified edge behavior 
     * will take affect.
     */

    public function get boundsCentre() : Vector3D
    {
        return _boundsCentre;
    }

    public function set boundsCentre( value : Vector3D ) : void
    {
        _boundsCentre = value;
    }

    /**
     * The maximum distance which this Boid can 
     * travel from it's boundsCentre before the 
     * specified edge behavior takes affect
     */

    public function get boundsRadius() : Number
    {
        return _boundsRadius;
    }

    public function set boundsRadius( value : Number ) : void
    {
        _boundsRadius = value;
    }    
    
    public function get position():Vector3D 
    {
        return _position;
    }
    
    public function set position(value:Vector3D):void 
    {
        _position = value;
    }
}