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: 布 :改善2 + 画像

2次元だけど、出来たかな?

あいかわらず右によってる。

ドラッグでマウスに一番近いポイントを移動させる。
ctrlキー押しながらドラッグで固定。
ダブルクリックで固定を解除。

import flash.geom.Point;
import flash.geom.Point;
// forked from kimo0517's 布 :改善2 + 画像
// forked from miniapp's 布 :改善2
/**
 * 2次元だけど、出来たかな?
 * 
 * あいかわらず右によってる。
 *
 * ドラッグでマウスに一番近いポイントを移動させる。
 * ctrlキー押しながらドラッグで固定。
 * ダブルクリックで固定を解除。
 * 
 *  
 */
package {
    //import flash.geom.Point;
    //import flash.geom.Point;
    import flash.display.Bitmap;
    import flash.display.Sprite;
    import flash.display.Loader;
    import flash.display.StageQuality;
    import flash.display.StageScaleMode;
    import flash.display.BitmapData;
    import flash.display.TriangleCulling;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.events.MouseEvent;
    import flash.net.FileReference;
    import flash.net.FileFilter;
    import flash.net.URLRequest;
    import com.bit101.components.PushButton;
    
    import mx.utils.Base64Decoder;

    [SWF(backgroundColor="0xAADDFF", width="465", height="465", frameRate="60")]
    public class Cloth extends Sprite {
        
        public static const STAGE_WIDTH:uint = 465;
        public static const STAGE_HEIGHT:uint = 465;
        
        private var btnSelectPic:PushButton;
        private var btnRemove:PushButton;
        
        private var bmd:BitmapData;
        private var _vseg:int;
        private var _hseg:int;
        
        private var vPos:Vector.<Number>;
        private var vIndex:Vector.<int>;
        private var uvtData:Vector.<Number>;
        
        private var fr:FileReference;
        
        public function Cloth() {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private var _lineColor:uint = 0x000000;
        private var _cols:uint = 16;//横の数
        private var _rows:uint = 16;//縦の数
        private var _diffX:uint = 10;
        private var _diffY:uint = 10;
        private var _isCtrlPress:Boolean = false;
        private var _isMouseDown:Boolean = false;
        private var _draggedPoint:Point;
        private var _isFirst:Boolean = false;
        private var _numJoints:uint;
        private var _joints:Vector.<Joint> = new Vector.<Joint>();
        private var _points:Vector.<Point> = new Vector.<Point>();
        private var _pointsXs:Vector.<Vector.<Point>> = new Vector.<Vector.<Point>>(_rows, true);
        private var _pointsYs:Vector.<Vector.<Point>> = new Vector.<Vector.<Point>>(_cols, true);
        
        private function init(e:Event = null):void {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            stage.scaleMode = StageScaleMode.NO_SCALE;
            //stage.quality = StageQuality.MEDIUM;
            
            stage.doubleClickEnabled = true;
            stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
            stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDwonHandler);
            stage.addEventListener(MouseEvent.DOUBLE_CLICK, doubleClickHandler);
            stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDonwHandler);
            stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
            
            bmd = null;
            btnSelectPic = new PushButton(this, 10, 10, "Select Photo", _btnSelectPicClicked);
            btnRemove = new PushButton(this, btnSelectPic.x + btnSelectPic.width + 10, 10, "Unload Photo", _btnUnloadPicClicked);
            
            _vseg = _cols;
            _hseg = _rows;
            var _vseg_1:int = _vseg - 1;
            var _hseg_1:int = _hseg - 1;
            var v:int;
            var h:int;
            
            vPos = new Vector.<Number>(2*_vseg * _hseg);
            uvtData = new Vector.<Number>(2*_vseg * _hseg);
            vIndex = new Vector.<int>(6 * _vseg_1 * _hseg_1);
            
            for (v = 0; v < _vseg; v++) {
                for (h = 0; h < _hseg; h++) {
                    //x
                    uvtData[2 * (v * _hseg + h)]         = Number(h) / _hseg_1;
                    uvtData[2 * (v * _hseg + h) + 1]     = Number(v) / _vseg_1;
                }
            }
            
            for (v = 0; v < _vseg_1; v ++ ) {
                for (h = 0; h < _hseg_1; h++) {
                    vIndex[6 * (v * _hseg_1 + h)]             = v * _hseg + h;
                    vIndex[6 * (v * _hseg_1 + h) + 1]         = v * _hseg + h+1;
                    vIndex[6 * (v * _hseg_1 + h) + 2]         = (v+1) * _hseg + h;
                    
                    vIndex[6 * (v * _hseg_1 + h) + 3]         = (v+1) * _hseg + h;
                    vIndex[6 * (v * _hseg_1 + h) + 4]         = v * _hseg + h+1;
                    vIndex[6 * (v * _hseg_1 + h) + 5]         = (v+1) * _hseg + h+1;
                }
            }
            
            putPoint();
            joint();
            
            //上端2つを固定します。
            //左端
            var point1:Point = _pointsXs[0][0];
            point1.x = 100;
            point1.y = 10;
            point1.isPinned = true;
            
            //右端
            var point2:Point = _pointsXs[0][_cols - 1];
            point2.x = STAGE_WIDTH - 100;
            point2.y = 10;
            point2.isPinned = true;
            
            var point3:Point = _pointsXs[_rows - 1][0];
            point3.x = 100;
            point3.y = STAGE_HEIGHT - 10;
            point3.isPinned = true;
            
            var point4:Point = _pointsXs[_rows - 1][_cols - 1];
            point4.x = STAGE_WIDTH - 100;
            point4.y = STAGE_HEIGHT - 10;
            point4.isPinned = true;
            
            var point5:Point = _pointsXs[0][int((_cols - 1) / 2)];
            point5.x = int(STAGE_WIDTH / 2);
            point5.y = 10;
            point5.isPinned = true;
            
            var point6:Point = _pointsXs[_rows - 1][int((_cols - 1) / 2)];
            point6.x = int(STAGE_WIDTH / 2);
            point6.y = STAGE_HEIGHT - 10;
            point6.isPinned = true;
            
            addEventListener(Event.ENTER_FRAME, enterFrameHandler);
            
            var decoder:Base64Decoder = new Base64Decoder;
            decoder.decode("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");
            
            var loader:Loader = new Loader;
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, _loadBMDComplete);
            loader.loadBytes(decoder.toByteArray());
        }
        
        private function _btnSelectPicClicked(e:MouseEvent):void {
            fr = new FileReference();
            fr.addEventListener(Event.SELECT, _startLoadPhoto);
            fr.addEventListener(Event.COMPLETE, _loadPhotoComplete);
            
            var filter:FileFilter = new FileFilter("Images (*.jpg, *.png)", "*.jpg;*.jpeg;*.png", null);
            
            fr.browse([filter]);
            
        }
        
        private function _startLoadPhoto(e:Event):void {
            fr.load();
        }
        
        private function _loadPhotoComplete(e:Event):void {
            var loader:Loader = new Loader();
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, _loadBMDComplete);
            loader.loadBytes(fr.data);
        }
        
        private function _loadBMDComplete(e:Event):void {
            if (bmd != null) {
                bmd.dispose();
                bmd = null;
            }
            bmd = e.target.content.bitmapData.clone();
        }

        
        private function _btnUnloadPicClicked(e:MouseEvent):void {
            if (bmd != null) {
                bmd.dispose();
                bmd = null;
            }
        }
        
        /**
         * ポイントを配置します。
         */
        private function putPoint():void {
            //縦方向に並べたポイントを入れる配列を先に用意する
            for (var i:uint = 0; i < _cols; i++) { 
                var pointsY:Vector.<Point> = new Vector.<Point>(_rows, true);
                _pointsYs[i] = pointsY;
            }
            
            var clothWidth:Number = (_cols - 1) * _diffX;
            var clothHeight:Number = (_rows - 1) * _diffY;
            var startX:Number = (STAGE_WIDTH - clothWidth) / 2;
            var startY:Number = (STAGE_HEIGHT - clothHeight) / 2;
            
            //ポイントを格子状に配置
            for (i = 0; i < _rows; i++) {
                var pointsX:Vector.<Point> = new Vector.<Point>(_cols, true);
                _pointsXs[i] = pointsX;
                for (var j:uint = 0; j < _cols; j++) {
                    var point:Point = new Point();
                    _points.push(point);
                    point.name = String(i) + "-" + String(j);//デバッグ用
                    point.x = startX + _diffX * j;
                    point.y = startY + _diffY * i;
                    
                    //横に並ぶポイントを入れる
                    pointsX[j] = point;
                    
                    //縦方向に並ぶポイントを入れる
                    pointsY = _pointsYs[j];
                    pointsY[i] = point;
                }
            }
            _points.fixed = true;
        }
        
        private function joint():void {
            for (var i:uint; i < _rows; i++) {
                for (var j:uint = 0; j < _cols; j++) {
                    var point:Point = _pointsXs[i][j];
                    if (j > 0) {
                        var leftPoint:Point = _pointsXs[i][j - 1 ];
                        _joints.push(new Joint(leftPoint, point));
                        _joints.push(new Joint(point, leftPoint));
                    }
                    
                    if (i > 0) {
                        var upPoint:Point = _pointsXs[i - 1][j];
                        _joints.push(new Joint(upPoint, point));
                        _joints.push(new Joint(point, upPoint));
                    }
                }
            }
            
            _numJoints = _joints.length;
            _joints.fixed = true;
        }
        
        /**
         * 一番カーソルに近いポイントを捜す。
         */
        private function searchPoint():Point {
            var lastMinDist:Number = Infinity;
            var target:Point;
            for each(var point:Point in _points) {
                var dx:Number = point.x - mouseX;
                var dy:Number = point.y - mouseY;
                var dist:Number = Math.sqrt(dx * dx + dy * dy);
                if (dist < lastMinDist) {
                    lastMinDist = dist;
                    target = point;
                }
            }
            return target;
        }
        
        /**
         * ポイント同士を繋ぐ線を書く
         */
        private function drawLine():void {
            graphics.clear();
            graphics.lineStyle(1, _lineColor);
            //横のラインを引く
            for each(var pointsX:Vector.<Point> in _pointsXs){
                //横列のポイントが入った配列にアクセス。
                var firstPoint:Point = pointsX[0];
                graphics.moveTo(firstPoint.x, firstPoint.y);
                for (var i:uint = 1; i < _cols; i++) {
                    var point:Point = pointsX[i];
                    graphics.lineTo(point.x, point.y);
                }
            }
            
            for each(var pointsY:Vector.<Point> in _pointsYs) {
                firstPoint = pointsY[0];
                graphics.moveTo(firstPoint.x, firstPoint.y);
                for (i = 1; i < _rows; i++) {
                    point = pointsY[i];
                    graphics.lineTo(point.x, point.y);
                }
            }
        }
        
        private function drawBMD():void {
            var v:int;
            var h:int;
            var i:int;
            
            v = 0;
            for each(var pointsX:Vector.<Point> in _pointsXs){
                i = 0;
                for (h = 0; h < _hseg; h++) {
                    vPos[2 * (v * _hseg + h)]         = pointsX[i].x; //x
                    vPos[2 * (v * _hseg + h) + 1]     = pointsX[i].y; //y
                    i++;
                }
                v++;
            }
            
            graphics.clear();
            graphics.beginBitmapFill(bmd, null, false, true);
            graphics.drawTriangles(vPos, vIndex, uvtData, TriangleCulling.NONE);
            graphics.endFill();
        }

        
        private function enterFrameHandler(e:Event):void {
            if (_isMouseDown) {
                _draggedPoint.x = mouseX;
                _draggedPoint.y = mouseY;
            }
            
            for each(var joint:Joint in _joints) {
                joint.update();
            }
            
            if (bmd == null) {
                drawLine();
            } else {
                drawBMD();
            }

        }
        
        private function keyDonwHandler(e:KeyboardEvent = null):void{
            if(e.ctrlKey) _isCtrlPress = true;
        }
        
        private function keyUpHandler(e:KeyboardEvent = null):void{
            _isCtrlPress = false;
        }
        
        private function doubleClickHandler(e:MouseEvent = null):void{
            searchPoint().isPinned = false;
        }
        
        private function mouseDwonHandler(e:MouseEvent):void {
            _isMouseDown = true;
            _draggedPoint = searchPoint();
            _draggedPoint.isDragging = true;
        }
        
        private function mouseUpHandler(e:MouseEvent):void    {
            _isMouseDown = false;
            if (_isCtrlPress)
                _draggedPoint.isPinned = true;
            _draggedPoint.isDragging = false;
            _draggedPoint = undefined;
        }
    }
}

class Joint {
    
    public static var SPRING:Number = 0.08;
    public static var FRICTION:Number = 0.96;
    public static var GRAVITY:Number = 0.45;
    
    public function Joint(point:Point, target:Point) { 
        var initDx:Number = target.x - point.x;
        var initDy:Number = target.y - point.y;
        var length:Number = Math.sqrt(initDx * initDx + initDy * initDy);
        
        //バネ運動させる関数
        update = function():void {
            if (point.isDragging || point.isPinned)
                return;
            
            var dx:Number = target.x - point.x;
            var dy:Number = target.y - point.y;
            /*
            var angle:Number = Math.atan2(dy, dx);
            var targetX:Number = target.x - length * Math.cos(angle);
            var targetY:Number = target.y - length * Math.sin(angle);
            /**/
            //*
            //Math.cos(angle) は dx / distanceと同じ
            //Math.sin(angle) は dy / distanceと同じ
            var distance:Number = Math.sqrt(dx * dx + dy * dy);
            var targetX:Number = target.x - length * dx / distance;
            var targetY:Number = target.y - length * dy / distance;
            /**/
            
            point.vx += (targetX - point.x) * Joint.SPRING;
            point.vy += (targetY - point.y) * Joint.SPRING;
            point.x += (point.vx *= FRICTION);
            point.y += (point.vy *= FRICTION);
            point.y += GRAVITY;
        }
    }
    
    public var update:Function;
}

class Point {
    public var name:String;
    public var x:Number;
    public var y:Number;
    public var z:Number;
    public var vx:Number = 0;
    public var vy:Number = 0;
    public var vz:Number = 0;
    public var isPinned:Boolean = false;
    public var isDragging:Boolean = false;
}