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

DevilTail

2010-04-20 23:42:28
/**
 * Copyright civet ( http://wonderfl.net/user/civet )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/ixGP
 */

// forked from tail_y's 黒猫の尻尾
// 2010-04-20 23:42:28
package
{
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.GradientType;
    import flash.display.Graphics;
    import flash.display.Sprite;
    import flash.display.StageQuality;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.events.MouseEvent;
    import flash.filters.BevelFilter;
    import flash.filters.BlurFilter;
    import flash.geom.ColorTransform;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.geom.Rectangle;

    public class DevilTail extends Sprite
    {
        
        public function DevilTail()
        {
            addEventListener(Event.ADDED_TO_STAGE, init);    // flexBuilderとの互換性。
            Wonderfl.capture_delay(4);
        }
        
        public static const STAGE_W:uint = 465;
        public static const STAGE_H:uint = 465;
        private static const _PI:Number = Math.PI;
        private static const _PI2:Number = 2.0 * _PI;
        
        private static const _WALL_LEFT:Number = 0;
        private static const _WALL_RIGHT:Number = 465;
        private static const _GROUND_LINE:Number = 400;
        
        
        private static const _DERIVATION:int = 4;
        
        private static const _GRAVITY:Number = 0.4 / _DERIVATION;
        private static const _ROTATION_RATE:Number = 0.05 / _DERIVATION;    // 自身バネ(根元)
        private static const _VERTICAL_RATE:Number = 0.5 / _DERIVATION;    // ターゲットバネ(さきっぽ)
        private static const _MOUSE_PULL_RATE:Number = 0.1 / _DERIVATION;
        
        private static const _FRICTION:Number = 1 - 0.1 / _DERIVATION;
        private static const _MOUSE_ROTATE_FRICTION:Number = 1 - 0.8 / _DERIVATION;
        private static const _MOUSE_MOVE_FRICTION:Number = 1 - 0.5 / _DERIVATION;
        
        private static const _COLOR:uint = 0x333344;
        private static const _BEVEL_H_COLOR:uint = 0x404050;
        private static const _BEVEL_S_COLOR:uint = 0x000000;
        
        private var _boneList:Array = [];
        private var _dragId:int = -1;
        private var _boneLayer:Sprite;
        private var _displayLayer:Sprite;
                  private var _arrow:Sprite;
        
        private var _shadowLayer:Bitmap;
        private var _shadow:BitmapData = new BitmapData(STAGE_W, STAGE_H, true, 0x00000000);
        private var _clear:BitmapData = new BitmapData(STAGE_W, STAGE_H, false, 0x888888);
        private var _cover:BitmapData = new BitmapData(STAGE_W, STAGE_H, true, 0x00000000);
        
        private var _bevel:BevelFilter = new BevelFilter(20, 100, _BEVEL_H_COLOR, 1, _BEVEL_S_COLOR, 1, 33, 33, 1, 1);
        
        private var _topLock:Boolean = true;
        private static const _LOCK_Y:int = 50;
        
        private function init(e:Event):void {    // ここから開始
            removeEventListener(Event.ADDED_TO_STAGE, init);
            // SWF設定
            stage.frameRate = 30;
            stage.quality = StageQuality.MEDIUM;
            var bg:Sprite = new Sprite();    // wonderflではキャプチャに背景色が反映されないので、背景色Spriteで覆う。
            bg.graphics.beginFill(0xffffff, 1);
            bg.graphics.drawRect(0, 0, STAGE_W, STAGE_H);
            addChild(bg);
            
            // 色々準備
            var coverGradient:Sprite = new Sprite();
            var matrix:Matrix = new Matrix()
            matrix.createGradientBox(STAGE_W, STAGE_H, Math.PI / 2, STAGE_W / 2, STAGE_H / 2)
            coverGradient.graphics.beginGradientFill(GradientType.LINEAR, [0xffffff, 0xffffff], [1, 0], [0, 230], matrix);
            coverGradient.graphics.drawRect(0, 0, STAGE_W, STAGE_H);
            _cover.draw(coverGradient);
            
            _shadowLayer = new Bitmap(_shadow);
            _displayLayer = new Sprite();
            _boneLayer = new Sprite();
            addChild(_shadowLayer);
            addChild(_displayLayer);
            addChild(_boneLayer);
            _boneLayer.alpha = 0;    // マウスを取ってもらうので、完全には消さない
            //_displayLayer.filters = [_bevel];
                           
            _arrow = new Sprite();
            _arrow.graphics.beginFill(_COLOR);
            _arrow.graphics.moveTo(10, 0);
            _arrow.graphics.lineTo(24, -18);
            _arrow.graphics.lineTo(-40, 0);
            _arrow.graphics.lineTo(24, 18);
            _arrow.graphics.lineTo(10, 0);
            _arrow.graphics.endFill();
            _displayLayer.addChild(_arrow);

            // 骨組みを用意する。
            var i:int=0;
            addBone(5, 5);
            addBone(5, 30);
            addBone(5, 30);
            addBone(5, 30);
            addBone(5, 30);
            addBone(5, 30);
            addBone(5, 30);
            addBone(5, 30);
            addBone(5, 30);
            addBone(2, 30);
            
            // ドラッグ解除
            stage.addEventListener(MouseEvent.MOUSE_UP, bornMouseUpEvent());
            // フレームの処理を登録
            addEventListener(Event.ENTER_FRAME, frame);
            // キーの処理を登録
            stage.addEventListener(KeyboardEvent.KEY_DOWN, key);
            
            
        }
        private var _id:int = 0;
        private var _lastX:Number = 50;
        private function addBone(radius:Number, connectLength:Number):void{
            var bone:BoneCircle = new BoneCircle(radius, connectLength);
            bone.y = _LOCK_Y;
            bone.x = _lastX;
            _boneList.push(bone);
            _boneLayer.addChild(bone);
            // マウスイベント
            bone.addEventListener(MouseEvent.MOUSE_DOWN, bornMouseDownEvent(_id++));
            
            _lastX += connectLength;
        }
        
        // フレーム挙動
        private function frame(event:Event):void{
            for (var i:int=0; i<_DERIVATION; i++){
                rotate();
                foce();
                move();
            }
            draw();
            drawShadow();
            debugDraw();
        }
        
        // ボーンの向きを決定する
        private function rotate():void{
            var l:int = _boneList.length;
            for (var i:int=0; i < l; i++){
                var baceBone:BoneCircle = _boneList[i];
                var targetBone:BoneCircle = _boneList[i+1];
                if (i + 1 < l){
                    calcConnectRForce(baceBone, targetBone, 0);
                    calcConnectRForce(targetBone, baceBone, _PI);
                }
                if (i == _dragId) baceBone.vr *= _MOUSE_ROTATE_FRICTION;
                
                baceBone.vr *= _FRICTION;    // 摩擦
                
            }
        }
        // 接続されたパーツの回転方向を計算する
        private function calcConnectRForce(baceBone:BoneCircle, targetBone:BoneCircle, connectAngle:Number):void{
            var angle:Number = Math.atan2(targetBone.y - baceBone.y, targetBone.x - baceBone.x);
            baceBone.vr += ajustRadian(angle - (connectAngle + baceBone.radian)) * _ROTATION_RATE;
        }
        
        // 力関係、加速度を整理する。
        private function foce():void{
            var i:int;
            var l:int = _boneList.length;
            var bone:BoneCircle;
            for (i=0; i < l; i++){
                bone = _boneList[i];
                bone.vy += _GRAVITY;
                
                if (_dragId == i){    // マウスで引っ張る
                    var vPoint:Point = pullForce(bone.x, bone.y, mouseX, mouseY, _MOUSE_PULL_RATE);
                    bone.vx += vPoint.x;
                    bone.vy += vPoint.y;
                }
                
                if (i + 1 < l){
                    calcConnectFoce(bone, _boneList[i+1], 0);
                    calcConnectFoce(_boneList[i+1], bone, _PI);
                }
                
                // 摩擦
                bone = _boneList[i];
                bone.vx *= _FRICTION;
                bone.vy *= _FRICTION;
                if (i == _dragId){
                    bone.vx *= _MOUSE_MOVE_FRICTION;
                    bone.vy *= _MOUSE_MOVE_FRICTION;
                }
                
            }
        }
        // 接続された2パーツの力を計算する
        private function calcConnectFoce(baceBone:BoneCircle, targetBone:BoneCircle, connectAngle:Number):void{
            var toAngle:Number = ajustRadian(connectAngle + baceBone.radian);
            var toX:Number = baceBone.x + Math.cos(toAngle) * baceBone.connectLength;
            var toY:Number = baceBone.y + Math.sin(toAngle) * baceBone.connectLength;
            var vx:Number = (targetBone.x - toX) * _VERTICAL_RATE;
            var vy:Number = (targetBone.y - toY) * _VERTICAL_RATE;
            baceBone.vx += vx;
            baceBone.vy += vy;
            targetBone.vx -= vx;
            targetBone.vy -= vy;
        }
        // ポイントx1 y1を、ポイントx2 y2へ、係数rateだけ移動させる場合の、XYの力を返す
        private function pullForce(x1:Number, y1:Number, x2:Number, y2:Number, rate:Number):Point{
            var point:Point = new Point();
            var distance:Number = calcDistance(x1, y1, x2, y2);
            
            var angle:Number = Math.atan2(y2 - y1, x2 - x1);
            point.x = Math.cos(angle) * distance * rate;
            point.y = Math.sin(angle) * distance * rate;
            return point;
        }
        // ポイントx1 y1から、ポイントx2 y2までの距離
        private function calcDistance(x1:Number, y1:Number, x2:Number, y2:Number):Number{
            return Math.sqrt(Math.pow(x2-x1, 2) + Math.pow(y2-y1, 2));
        }
        // radian角度を、-π~πの範囲に修正する
        private function ajustRadian(radian:Number):Number{
            return radian - _PI2 * Math.floor( 0.5 + radian / _PI2);
        }
        
        // 移動を反映。
        private function move():void{
            for (var i:int=0; i < _boneList.length; i++){
                var bone:BoneCircle = _boneList[i];
                bone.x += bone.vx;
                bone.y += bone.vy;
                bone.radian += bone.vr;
                // 壁チェック
                if (0 < bone.vy && _GROUND_LINE - bone.radius < bone.y){
                    bone.y = _GROUND_LINE - bone.radius;
                    bone.vy = 0;
                }
                if (bone.vx < 0 && bone.x < _WALL_LEFT + bone.radius){
                    bone.x = _WALL_LEFT + bone.radius;
                    bone.vx = 0;
                }else if (0 < bone.vx && _WALL_RIGHT - bone.radius < bone.x){
                    bone.x = _WALL_RIGHT - bone.radius;
                    bone.vx = 0;
                }
                // 回転方向を反映
                bone.rotation = bone.radian * 180 / Math.PI;
            }
            if (_topLock){
                bone = _boneList[_boneList.length - 1];
                bone.vy = 0;
                bone.y = _LOCK_Y;
            }
        }
        
        
        // 表示。
        private function draw():void{
            var pointListX:Array = [];
            var pointListY:Array = [];

                           var bone:BoneCircle;
                           
                           //ARROW
                           bone = _boneList[0];
            _arrow.x = bone.x;
            _arrow.y = bone.y;
            _arrow.rotation = bone.radian * (180 / _PI);

            var i:int;
            var l:int = _boneList.length;
            for (i=0; i < l; i++){
                bone = _boneList[i];
                var cosR:Number = Math.cos(bone.radian + _PI/2)*bone.radius;
                var sinR:Number = Math.sin(bone.radian + _PI/2)*bone.radius;
                pointListX.push(bone.x + cosR);
                pointListY.push(bone.y + sinR);
                pointListX.unshift(bone.x - cosR);
                pointListY.unshift(bone.y - sinR);
                           }
            var g:Graphics = _displayLayer.graphics;
            g.clear();
            g.beginFill(_COLOR, 1);
            l = pointListX.length - 1;
            i = 0;
            var baceX:Number = (pointListX[i] + pointListX[i+1])/2;
            var baceY:Number = (pointListY[i] + pointListY[i+1])/2;
            g.moveTo(baceX, baceY);
            for (i=1; i < l; i++){
                g.curveTo(pointListX[i], pointListY[i], (pointListX[i] + pointListX[i+1])/2, (pointListY[i] + pointListY[i+1])/2);
            }
            g.lineTo(baceX, baceY);
        }
        
        private var _rect:Rectangle = new Rectangle(0, 0, STAGE_W, STAGE_H);
        private var _point:Point = new Point();
        private var _shadowMatrix:Matrix = new Matrix(1, 0, 0, 0.5, 0, STAGE_H/2-30);
        private var _shadowColor:ColorTransform = new ColorTransform(0,0,0,1, 0,0,0,0);
        private var _shadowBlur:BlurFilter = new BlurFilter(30, 30, 1);
        private function drawShadow():void{
            _shadow.lock();
            _shadow.copyPixels(_clear, _rect, _point);
            _shadow.draw(_displayLayer, _shadowMatrix, _shadowColor);
            _shadow.applyFilter(_shadow, _rect, _point, _shadowBlur);
            _shadow.draw(_cover);
            _shadow.unlock();
        }
        
        // デバッグ表示。
        private function debugDraw():void{    
            
        }
        
        // マウスイベント
        private function bornMouseDownEvent(i:int):Function{
            return function (event:Event):void{    startBornDrag(i);};
        }
        private function bornMouseUpEvent():Function{
            return function (event:Event):void{    endBornDrag();};
        }
        
        // ドラッグ
        private function startBornDrag(bornNum:int):void{
            _dragId = bornNum;
        }
        private function endBornDrag():void{
            _dragId = -1;
        }
        
        private function key(event:KeyboardEvent):void{
            if (event.keyCode == 76){    // L
                trace("changeLock");
                _topLock = !_topLock;
            }
            if (event.keyCode == 68){    // D
                trace("changeDisplay");
                _boneLayer.alpha = _boneLayer.alpha ? 0 : 1;
            }
        }
    }
}
    import flash.display.Sprite;
    
class BoneCircle extends Sprite
{
    public var radius:Number;    // 半径
    public var connectLength:Number;    // 次パーツとのつながりの長さ
    
    public var radian:Number = 0;    // 一時的な回転量。
    
    public var vx:Number = 0;
    public var vy:Number = 0;
    public var vr:Number = 0;
    
    public function BoneCircle(radius:Number, connectLength:Number)
    {
        this.radius = radius;
        this.connectLength = connectLength;
        
        graphics.beginFill(0xff0000, 0.02);
        graphics.lineStyle(0, 0, 0);
        graphics.drawCircle(0, 0, radius + 20);
        
        graphics.beginFill(0x0000ff, 0.3);
        graphics.lineStyle(1, 0x000088, 1);
        graphics.drawCircle(0, 0, radius);
        
        graphics.moveTo(-radius + 10, 0);
        graphics.lineTo(radius + 10, 0);
        
        
    }
}