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: Button

Alternativa3DおよびBox2Dの習作。
余計な事をせずに「なるべく自立するトランプタワー」を目指してみました。
Get Adobe Flash player
by AtuyL 23 Oct 2012
/**
 * Copyright AtuyL ( http://wonderfl.net/user/AtuyL )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/qVmD
 */

// forked from Event's Button
/** トランプタワー破壊 ボタン
 * 
 * @author AtuyL
 * 
 * トランプタワーって崩したくなるよね(´・ω・)
 * 
 * 今日は思う存分やってね。
 * トランプは勝手に積み上がっていくからね。
 * PUTボタンを使えば自分で積み上げる事も出来るけど、タイミングを見計らってカードを置かないと崩れちゃうよ。
 * 後片付けはCLEARボタンを押してね。
 * 
 * なるべく軽くしようとコリジョン形状を工夫したけど、
 * それでもあんまり段数多くすると超重いよ。
 * 
 * 最後あたり突貫工事でソース汚くしちゃってごめんね J(’ー`)し
 * アップロード直前にwonderflのAlternativa3Dのバージョンが最新になってるのに気が付いて超焦った。
 * 全くの別物になっててびっくりしたよ。
 * だれか7.5にて両面に別々のUV張る方法おしえてください(´・ω・)以前は簡単にできたのに…
 * 
 * ※:@narutohyper 氏にアドバイスいただき、チラつきを抑えたバージョンに変更しました。
 */
 
package{
    import alternativ7.engine3d.containers.BSPContainer;
    import alternativ7.engine3d.containers.ConflictContainer;
    import alternativ7.engine3d.containers.DistanceSortContainer;
    import alternativ7.engine3d.containers.KDContainer;
    import alternativ7.engine3d.controllers.SimpleObjectController;
    import alternativ7.engine3d.core.Camera3D;
    import alternativ7.engine3d.core.Geometry;
    import alternativ7.engine3d.core.Object3DContainer;
    import alternativ7.engine3d.core.Sorting;
    import alternativ7.engine3d.core.Transform3D;
    import alternativ7.engine3d.core.View;
    import alternativ7.engine3d.materials.FillMaterial;
    import alternativ7.engine3d.primitives.Plane;
    import alternativ7.engine3d.core.Face;
    import alternativ7.engine3d.materials.TextureMaterial;
    import com.bit101.components.*;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Loader;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Matrix;
    import flash.geom.Matrix3D;
    import flash.geom.Point;
    import flash.geom.Vector3D;
    import flash.net.URLRequest;
    import flash.utils.setTimeout;
    import flash.system.LoaderContext;
     
    [SWF(width=465,height=465,backgroundColor=0xFFFFFF,frameRate=60)]
    public class Main extends Sprite{
        private var content:Sprite;
        private var ui:Sprite;
        
        public function Main(){
            this.preload();
        }
        
        private var loadlist:Array = [
            {url:"http://assets.wonderfl.net/images/related_images/6/68/68fc/68fc116ad5920aa4dc69540835e854581794e8f3",key:"floorTexture"},
            {url:"http://assets.wonderfl.net/images/related_images/a/a1/a151/a151b4db9de05b302de3d6316bc20b4c0d6b173e",key:"cardTexture"},
        ];
        
        // asset image の読み込み
        public function preload():void{
            var target:Main = this;
            var current:Object = loadlist.shift();
            var loader:Loader = new Loader();
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE,function(event:Event):void{
                event.currentTarget.removeEventListener(event.type,arguments.callee);
                target[current.key] = Bitmap(loader.content).bitmapData.clone();
                if(loadlist.length) preload();
                else init();
            });
            loader.load(new URLRequest(current.url),new LoaderContext(true));
        }
        
        public function init():void{
            this.addChild(this.content = new Sprite);
            this.addChild(this.ui = new Sprite);
            
            this.init3D();
            this.initCardTower();
            
            
            // 各種 ui を設置
            var offset:Number = 24;
            var x:Number = (this.stage.stageWidth - offset * 2.0) >> 2;
            var y:Number = this.stage.stageHeight - 64;
            
            
            
            
            
            this.stage.addEventListener(Event.ENTER_FRAME,enterframe);
            
            var button:PushButton;
            button = new PushButton(this.ui,0,0,"BREAK",function(event:MouseEvent):void{
                 // 頂点位置モデル
                 // A B
                 // D C
                var poly:Polygon = new Polygon(Vector.<Vertex>([
                    new Vertex(-0.3,-0.3),// A
                    new Vertex( 0.3,-0.3),// B
                    new Vertex( 0.3, 0.3),// C
                    new Vertex(-0.3, 0.3) // D
                ]));
                poly.x = (Math.random() - 0.5) * 0.5;
                poly.y = -cardtower.rowLength * 0.5;
                poly.rotation = Math.PI * Math.random();
                poly.restitution = 1.0;
                box2d.addChild(poly);
                
            });
            button.width = 128;
            button.height = 128;
            
            var slider:HUISlider = new HUISlider(this.ui,0,0,"ROW");
            slider.maximum = 8;
            slider.value = 4;
            slider.addEventListener(Event.CHANGE,function(event:Event):void{
                init3D();
                initCardTower(slider.value);
            });
            slider.x = 138;
            slider.y = 128 - offset * 1;
            
            new PushButton(this.ui,138,128 - offset * 2,"PUT",function(event:MouseEvent):void{
                putCard();
                framecount = 0;
            })
            new PushButton(this.ui,138,128 - offset * 3,"RESET",function(event:MouseEvent):void{
                init3D();
                initCardTower(slider.value);
                while(cardtower.cardlist.length > numCards) putCard();
            })
            new PushButton(this.ui,138,128 - offset * 4,"CLEAR",function(event:MouseEvent):void{
                init3D();
                initCardTower(slider.value);
                framecount = 0;
            });
            
            this.ui.x = 10;
            this.ui.y = this.stage.stageHeight - 138;
            
            while(cardtower.cardlist.length > numCards) putCard();
        }
        
        private var numCards:int;
        public function putCard():void{
            if(this.cardtower.cardlist.length <= this.numCards) return;
            
            this.numCards++;
            
            var size:Number = 0.1618;
            var thickness:Number = size * 0.05;
            var card:Card = this.cardtower.cardlist[this.cardtower.cardlist.length - this.numCards];
            
            
            // create 2D-CardTower
            var verticles:Vector.<Vertex>;
            if(!card.isBridge){
                var cos:Number = Math.cos(Math.abs(card.radian)) * thickness * 2.0;
                var sin:Number = Math.sin(Math.abs(card.radian)) * thickness * 2.0;
                
                // offset1,offset2
                var o1:Number,o2:Number;
                if(card.radian < 0){
                    o1 = sin;
                    o2 = cos;
                }else{
                    o1 = cos;
                    o2 = sin;
                }
                
                // 頂点位置モデル
                //   A
                //  F B
                //  E C
                //   D
                verticles = Vector.<Vertex>([
                    new Vertex(  0.0 , -size      ),// A
                    new Vertex(  o1  , -size + o2 ),// B
                    new Vertex(  o2  ,  size - o1 ),// C
                    new Vertex(  0.0 ,  size      ),// D
                    new Vertex( -o1  ,  size - o2 ),// E
                    new Vertex( -o2  , -size + o1 ) // F
                ]);
            }else{
                // 頂点位置モデル
                //  A B
                //  D C
                verticles = Vector.<Vertex>([
                    new Vertex( -thickness , -size ),// A
                    new Vertex(  thickness , -size ),// B
                    new Vertex(  thickness ,  size ),// C
                    new Vertex( -thickness ,  size ),// D
                ]);
            }
            
            var polygon:Polygon = new Polygon(verticles);
            polygon.x = card.x * size * 2.0;
            polygon.y = card.y * size * 2.0 - 0.02;
            //if(card.isBridge && card.isOdd) polygon.y += 0.01;
            polygon.rotation = -card.radian;
            polygon.density = 0.01;
            polygon.friction = 0.4;
            polygon.restitution = 0.0;
            this.box2d.addChild(polygon,false);
            this.cardlist2D.push(polygon);
            
            
            // create 3D-CardTower from 2D-CardTower
            var rotationAxis:Vector3D = new Vector3D(0,1,0);
            var rotationMatrix:Matrix3D = new Matrix3D();
            
            //
            // for @narutohyper
            //     thanks for advise !!
            //
            
            var card3D:Plane = new Plane(100.0,161.8,1,1,true);
            card3D.z = Math.random();
            
            var vertices:Vector.<alternativa.engine3d.core.Vertex>;
            var vertex:alternativa.engine3d.core.Vertex;
            
            var position:Vector3D;
            var normal:Vector3D;
            var rotation:Matrix3D = new Matrix3D();
            rotation.appendRotation(!card.isBridge && card.isOdd ? 90 : -90,Vector3D.Y_AXIS);
            var geometry:Geometry = card3D.geometry;
            geometry.transform(rotation);
            card3D.geometry = geometry;
            
            var frontFace:Face = card3D.faces[0];
            var backFace:Face = card3D.faces[1];
            
            frontFace.material = backFace.material = new TextureMaterial(this.cardTexture,false,true);
            
            // texture consts
            const textureWidth:Number = 392;
            const textureHeight:Number = 640;
            const spriteWidth:Number = 56;
            const spriteHeight:Number = 80;
            
            var uvX:Number =  336 / textureWidth;
            var uvY:Number =  spriteHeight / textureHeight;
            var uvW:Number =  spriteWidth  / textureWidth;
            var uvH:Number =  spriteHeight / textureHeight;
            
            
            // frontface uv
            vertex = frontFace.vertices[0];
            vertex.u = uvX + uvW;
            vertex.v = uvY;
            
            vertex = frontFace.vertices[1];
            vertex.u = uvX + uvW;
            vertex.v = uvY + uvH;
            
            vertex = frontFace.vertices[2];
            vertex.u = uvX;
            vertex.v = uvY + uvH;
            
            vertex = frontFace.vertices[3];
            vertex.u = uvX;
            vertex.v = uvY;
            
            // backface uv
            var xIndex:int = (Math.random() * 7) >> 0;
            var yIndex:int = (Math.random() * 8) >> 0;
            uvX = spriteWidth * xIndex / textureWidth;
            uvY = spriteHeight * yIndex / textureHeight;
            
            vertex = backFace.vertices[0];
            vertex.u = uvX + uvW;
            vertex.v = uvY + uvH;
            
            vertex = backFace.vertices[1];
            vertex.u = uvX;
            vertex.v = uvY + uvH;
            
            vertex = backFace.vertices[2];
            vertex.u = uvX;
            vertex.v = uvY;
            
            vertex = backFace.vertices[3];
            vertex.u = uvX + uvW;
            vertex.v = uvY;
            
            card3D.sorting = Sorting.DYNAMIC_BSP;
            card3D.optimizeForDynamicBSP(2);
            
            this.cardlist3D.push(this.world.addChild(card3D));
            
            if(!card.isBridge && !card.isOdd) putCard(); // ペア設置
        }
        
        private var box2d:Box2D;
        private var box2dCanvas:Sprite;
        private var cardtower:CardTower;
        private var cardlist2D:Vector.<Polygon>;
        private var cardlist3D:Vector.<Plane>;
        public function initCardTower(row:int = 4):void{
            this.cardtower = new CardTower(row);
            
            // init box2d and debugdraw
            var calcSize:Number = 10.0;
            this.box2d = new Box2D(-calcSize,-calcSize,calcSize,calcSize);
            
            // 頂点位置モデル
            //  A B
            //  D C
            var floor:Polygon = new Polygon(
                Vector.<Vertex>([
                    new Vertex(-calcSize,-calcSize * 0.5),// A
                    new Vertex( calcSize,-calcSize * 0.5),// B
                    new Vertex( calcSize, calcSize * 0.5),// C
                    new Vertex(-calcSize, calcSize * 0.5),// D
                ])
            );
            floor.x = 0.0;
            floor.y = calcSize * 0.5;
            floor.rotation = 0.0;
            floor.density = 0.0;
            floor.friction = 0.8;
            floor.restitution = 0.0;
            this.box2d.addChild(floor,true);
            
            this.cardlist2D = new Vector.<Polygon>();
            this.cardlist3D = new Vector.<Plane>();
            this.offsetlist = new Vector.<Matrix>(this.cardtower.cardlist.length);
            this.numCards = 0;
        }
        
        private var scene:DistanceSortContainer;
        private var world:ConflictContainer;
        private var camera:Camera3D;
        private var viewport:View;
        
        private var floorTexture:BitmapData;
        private var cardTexture:BitmapData;
        
        public function init3D():void{
            var stageWidth:Number = this.stage.stageWidth;
            var stageHeight:Number = this.stage.stageHeight;
            
            this.viewport = new View(stageWidth,stageHeight);
            
            this.scene = new DistanceSortContainer();
            this.scene.sortByZ = true;
            this.world = new ConflictContainer();
            this.world.threshold = 2;
            this.scene.addChild(this.world);
            
            this.camera = new Camera3D();
            this.camera.y = -1000;
            this.camera.z = -2000;
            this.camera.fov = Math.PI * 0.6;
            this.camera.view = this.viewport;
            this.scene.addChild(this.camera);
            
            var floor:Plane = new Plane(2000,2000,1,1,true);
            floor.y = 100;
            floor.rotationX = Math.PI * 0.5;
            floor.setMaterialToAllFaces(new TextureMaterial(floorTexture.clone()));
            this.scene.addChild(floor);
            
            this.content.addChild(this.viewport);
        }
        
        private var offsetlist:Vector.<Matrix>;
        public function sync():void{
            for(var i:int;i < this.numCards;i++){
                var card2D:Polygon = this.cardlist2D[i];
                var card3D:Plane = this.cardlist3D[i];
                
                var matrix2D:Matrix = card2D.getMatrix();
                var matrix3D:Matrix3D = card3D.matrix;
                
                var rawData:Vector.<Number> = matrix3D.rawData;
                rawData[0] = matrix2D.a;//  cosθ
                rawData[1] = matrix2D.b;//  sinθ
                rawData[4] = matrix2D.c;// -sinθ
                rawData[5] = matrix2D.d;//  cosθ
                rawData[12] = matrix2D.tx * 500;
                rawData[13] = matrix2D.ty * 500;// y+ が上方向のため
                matrix3D.rawData = rawData;
                
                card3D.matrix = matrix3D;
                
                // 落下に従って適当にバラつかせる
                var offset:Matrix = this.offsetlist[i] || new Matrix(1,0,0,1,matrix2D.tx,matrix2D.ty);
                var offsetX:Number = matrix2D.tx - offset.tx;
                var offsetY:Number = matrix2D.ty - offset.ty;
                offsetY = card3D.z < 0 ? -offsetY : offsetY;
                this.offsetlist[i] = matrix2D;
                card3D.z += offsetY * 50;
                card3D.rotationX += offsetX * 0.1;
                
            }
        }
        
        public function orbitMove(pitch:Number,yaw:Number):void{
            var orbit:Matrix3D = new Matrix3D();
            orbit.appendTranslation(0,0,-100 - 100 * this.cardtower.rowLength);
            orbit.appendRotation(pitch / Math.PI * 180,new Vector3D(1,0,0));
            orbit.appendRotation(yaw / Math.PI * 180,new Vector3D(0,1,0));
            this.camera.matrix = orbit;
            this.camera.y -= 80 * this.cardtower.rowLength;
            
        }
        
        private var framecount:int;
        private function enterframe(event:Event = null):void{
            if(!(++framecount % 120)){
                this.putCard();
                framecount = 0;
            }
            
            this.box2d.nextFrame();
            
            this.sync();
            
            var yaw:Number = (this.stage.mouseX / this.stage.stageWidth - 0.5) * -Math.PI * 0.5;
            var pitch:Number = Math.sin((this.stage.mouseY / this.stage.stageHeight - 1.0) * Math.PI * 0.5) * Math.PI * 0.5;
            this.orbitMove(pitch,yaw);
            
            this.camera.render();
        }
    }
}

import Box2D.Collision.b2AABB;
import Box2D.Collision.Shapes.b2CircleDef;
import Box2D.Collision.Shapes.b2PolygonDef;
import Box2D.Collision.Shapes.b2ShapeDef;
import Box2D.Common.Math.b2Vec2;
import Box2D.Common.Math.b2XForm;
import Box2D.Dynamics.b2Body;
import Box2D.Dynamics.b2BodyDef;
import Box2D.Dynamics.b2DebugDraw;
import Box2D.Dynamics.b2World;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.geom.Matrix;
import flash.geom.Point;


class Card{
    public var x:Number;
    public var y:Number;
    public var radian:Number;
    public var isBridge:Boolean;
    public var isOdd:Boolean;
    public function Card(x:Number = 0.0,y:Number = 0.0,radian:Number = 0.0,isBridge:Boolean = false,isOdd:Boolean = false){
        this.x = x;
        this.y = y;
        this.radian = radian;
        this.isBridge = isBridge;
        this.isOdd = isOdd;
    }
}

class CardTower{
    private var radian:Number = Math.PI * 0.1;
    
    public function CardTower(rowLength:int = 4):void{
        this.rowLength = rowLength;
        this.cardlist = new Vector.<Card>();
        
        this.radian = Math.abs(this.radian);// ペアカードを正しく配置するため、回転値は必ず正である必要がある
        var cardW:Number = Math.sin(this.radian);// 回転角を適用後のカードを囲む矩形の横幅
        var cardH:Number = Math.cos(this.radian);// 回転角を適用後のカードを囲む矩形の縦幅
        
        for(var rowIndex:int = 0;rowIndex < rowLength;rowIndex++){
            var row:Number = rowLength - rowIndex;
            var clmLength:int = rowIndex + 1;
            
            var pairCardList:Vector.<Card> = new Vector.<Card>;
            var bridgeCardList:Vector.<Card> = new Vector.<Card>;
            for(var clmIndex:int = 0;clmIndex < clmLength;clmIndex++){
                var clm:Number = clmIndex - rowIndex * 0.5;
                
                var cardX:Number = clm * cardW *  2.0;// 左右1対で2枚分
                var cardY:Number = row * cardH * -1.0;// 下から上に積み上げる
                
                pairCardList.push(
                    this.addCard(cardX,cardY,-this.radian,true),
                    this.addCard(cardX,cardY, this.radian,false)
                );
                
                if(clmLength < rowLength){
                    bridgeCardList.push(
                        this.addBridge(cardX,cardY + cardH,Boolean(clmIndex % 2))
                    );
                }
            }
            
            var card:Card;
            for each(card in pairCardList) this.cardlist.push(card);
            for each(card in bridgeCardList) this.cardlist.push(card);
        }
    }
    public var rowLength:int;
    public var cardlist:Vector.<Card>;
    
    public function addCard(x:Number,y:Number,radian:Number,isOdd:Boolean):Card{
        var boundX:Number = Math.sin(radian) * 0.5;
        var boundY:Number = Math.cos(radian) * 0.5;
        return new Card(x + boundX,y + boundY,radian,false,isOdd);
    }
    
    public function addBridge(x:Number,y:Number,isOdd:Boolean):Card{
        return new Card(x,y,Math.PI * 0.5,true,isOdd);
    }
}

class Box2D{
    private var world:b2World = null;
    public function setDebugDraw(canvas:Sprite,drawScale:Number):void{
        var debugDraw:b2DebugDraw = new b2DebugDraw();
        debugDraw.m_sprite = canvas;
        debugDraw.m_drawScale = drawScale; // 1ポイントをdrawScale(px)として描画する
        debugDraw.m_fillAlpha = 0; // 塗りの不透明度
        debugDraw.m_lineThickness = 0.1; // 線の太さ
        debugDraw.m_drawFlags = b2DebugDraw.e_shapeBit;// | b2DebugDraw.e_coreShapeBit | b2DebugDraw.e_jointBit;
        this.world.SetDebugDraw(debugDraw);
    }
    
    public function Box2D(left:Number = -1.0,top:Number = -1.0,right:Number = 1.0,bottom:Number = 1.0){
        const GRAVITY:Number = 9.80665 * 0.5;
        
        var aabb:b2AABB = new b2AABB();
        aabb.lowerBound.Set(left,top);
        aabb.upperBound.Set(right,bottom);
        var gravity:b2Vec2 = new b2Vec2(0,GRAVITY);
        this.world = new b2World(aabb,gravity,true);
    }
    
    public function setGravity(x:Number,y:Number):void{
        this.world.SetGravity(new b2Vec2(x,y));
    }
    
    public function addChild(child:Box2DBody,isStatic:Boolean = false):void{
        child.updateProperties();
        
        child.boxBody = this.world.CreateBody(child.boxBodyDef);
        child.boxBody.CreateShape(child.boxShapeDef);
        
        child.updatePosition();
        
        if(!isStatic) child.boxBody.SetMassFromShapes();
    }
    
    public function removeChild(child:Box2DBody):void{
        if(!child.boxBody) return;
        this.world.DestroyBody(child.boxBody);
        child.boxBody = null;
    }
    
    public function nextFrame():void{
        this.world.Step(1/60,10);
    }
}

class Box2DBody{
    internal var boxBody:b2Body;
    internal var boxBodyDef:b2BodyDef;
    internal var boxShapeDef:b2ShapeDef;
    public function Box2DBody(){
        this.boxBodyDef = new b2BodyDef();
        this.matrix = new Matrix();
    }
    
    public var x:Number = 0.0;
    public var y:Number = 0.0;
    public var rotation:Number = 0.0;
    public var density:Number = 0.5;// 密度
    public var friction:Number = 0.5;// 摩擦係数
    public var restitution:Number = 0.5;// 反発係数
    
    public function updatePosition():void{
        if(this.boxBody){
            var position:b2Vec2 = this.boxBody.GetPosition();
            position.Set(this.x,this.y);
            this.boxBody.SetXForm(position,this.rotation);
        }
    }
    public function updateProperties():void{
        if(this.boxShapeDef){
            this.boxShapeDef.density = this.density;
            this.boxShapeDef.friction = this.friction;
            this.boxShapeDef.restitution = this.restitution;
        }
    }
    
    private var matrix:Matrix;
    public function getMatrix():Matrix{
        if(!this.boxBody) return null;
        var xform:b2XForm = this.boxBody.GetXForm();
        this.matrix.a = xform.R.col1.x;
        this.matrix.b = xform.R.col1.y;
        this.matrix.c = xform.R.col2.x;
        this.matrix.d = xform.R.col2.y;
        this.matrix.tx = xform.position.x;
        this.matrix.ty = xform.position.y;
        return this.matrix.clone();
    }
}

class Polygon extends Box2DBody{
    public function Polygon(varticles:Vector.<Vertex>){
        super();
        
        var def:b2PolygonDef = new b2PolygonDef();
        def.vertexCount = varticles.length;
        var vertexIndex:int = 0;
        for(var i:int = 0,length:int = varticles.length;i < length;i++){
            var v:Vertex = varticles[i];
            var vertex:b2Vec2 = def.vertices[i];
            vertex.Set(v.x,v.y);
        }
        
        this.boxShapeDef = def;
    }
}

class Vertex{
    public var x:Number;
    public var y:Number;
    public function Vertex(x:Number,y:Number){
        this.x = x;
        this.y = y;
    }
}

class Circle extends Box2DBody{
    public function Circle(radius:Number){
        super();
        
        var def:b2CircleDef = new b2CircleDef();
        def.radius = radius;
        
        this.boxShapeDef = def;
    }
}