Beautifl - Flash Gallery

Thumbnail : [Box2D][PV3D] Elevator
[Box2D][PV3D] Elevator
clockmaker 2009-08-27 MIT License

再生するにはFlash Playerが必要です。デスクトップのブラウザでご覧ください。

/*===================================================*//**
 * Box2DAS3 and Papervision3D Demo
 * ドラッグで3Dを回転できます。
 * マウスホイールで拡大できます。
 * 後ろ側の緑色のはBox2Dの2次元表示です。
 * 
 * rsakane さんの投稿から Folk させていただきました。
 *
 * @author Yasu
 * @see http://clockmaker.jp/blog/
 * @since 2009.04.02
 *//*===================================================*/
package
{
    import Box2D.Collision.Shapes.*;
    import Box2D.Collision.b2AABB;
    import Box2D.Common.Math.b2Vec2;
    import Box2D.Dynamics.Joints.*;
    import Box2D.Dynamics.*;
    
    import org.papervision3d.cameras.CameraType;
    import org.papervision3d.materials.utils.MaterialsList;
    import org.papervision3d.render.QuadrantRenderEngine;
    
    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;
    import flash.net.*;
    import flash.ui.*;
    import flash.utils.getTimer;
    import flash.utils.Timer;
    
    import org.papervision3d.events.*;
    import org.papervision3d.lights.*;
    import org.papervision3d.materials.shadematerials.*;
    import org.papervision3d.objects.*;
    import org.papervision3d.view.*;
    import org.papervision3d.objects.primitives.*;
    
    import caurina.transitions.Tweener;
    
    [SWF(width="465", height="465", frameRate="60", backgroundColor="0xFFFFFF")]
    public class Main extends BasicView
    {
        // const vars
        static public const OBJ_SIZE:int = 20;
        static public const OBJ_COLOR:uint = 0x666666;
        
        static private const CAMERA_DISTANCE:int = 1000;
        
        // vars for Box2D
        private var worldWidth:Number;
        private var worldHeight:Number;
        private var m_iterations:int;
        private var m_wallWidth:Number;
        private var m_wallHeight:Number;
        private var m_timeStep:Number;
        private var m_physScale:Number;
        private var m_world:b2World;
        private var m_mouseJoint:b2MouseJoint;
        private var m_draggedBody:b2Body;
        private var mouseXWorldPhys:Number;
        private var mouseYWorldPhys:Number;
        private var isMouseDown:Boolean;
        private var arrayIndex:int;
        
        // array of objs
        private var pv3dObjsArr:Vector.<DisplayObject3D> = new Vector.<DisplayObject3D>();
        private var box3dSpapesArr:Vector.<b2Body> = new Vector.<b2Body>();
        
        // pv3d objs
        private var light:PointLight3D;
        private var mat:FlatShadeMaterial;
        
        // timer count
        private var timerCnt:int = 0;
        
        /**
         * Constructor
         */
        public function Main()
        {
            stage.quality = StageQuality.MEDIUM;
            
            Mouse.cursor = MouseCursor.HAND;
            
            // init PV3D
            super(stage.stageWidth, stage.stageHeight, false, false, CameraType.FREE);
            
            // init PV3D World
            createPaervision3dWorld();
            
            // init Box2D World
            createBox2dWorld()
            
            // addEvent
            addEventListener(Event.ENTER_FRAME, enterFrameHandler);
            
            // Backgound
            createBackGround();
            //cerateFullScreenBtn();
            
            // mouse interactive
            stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
            stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
            stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
            stage.addEventListener(MouseEvent.MOUSE_WHEEL, onMouseWheel);
        }
        
        
        
        /**
         * Create Papervision3D World
         */
        private function createPaervision3dWorld():void
        {
            camera.x = 0;
            camera.z = -CAMERA_DISTANCE;
            
            // heavy....
            //renderer = new QuadrantRenderEngine(QuadrantRenderEngine.CORRECT_Z_FILTER);
            
            // create light
            light = new PointLight3D();
            light.z = -100;
            
            mat = new FlatShadeMaterial(light, OBJ_COLOR);
            ballMat = new FlatShadeMaterial(light, 0x990000);
            
            cameraTarget = new DisplayObject3D();
            cameraTarget.x = -50; 
            cameraTarget.y = 50; 
        }
        
        /**
         * Create Box2D World
         */
        private function createBox2dWorld():void
        {
            // init Box2D
            worldWidth = stage.stageWidth;
            worldHeight = stage.stageHeight;
            m_iterations = 10;
            m_timeStep = 1 / stage.frameRate;
            m_physScale = 60;
            
            var worldAABB:b2AABB = new b2AABB();
            worldAABB.lowerBound.Set( -1000, -1000);
            worldAABB.upperBound.Set(1000, 1000);
            var gravity:b2Vec2 = new b2Vec2(0, 10);
            var doSleep:Boolean = true;
            m_world = new b2World(worldAABB, gravity, doSleep);
            
            var dbgDraw:b2DebugDraw = new b2DebugDraw();
            dbgDraw.m_sprite = this;
            dbgDraw.m_drawScale = SCALE;
            dbgDraw.m_fillAlpha = 0.3;
            dbgDraw.m_lineThickness = 1.0;
            dbgDraw.m_alpha = 1.0;
            dbgDraw.m_xformScale = 1.0
            dbgDraw.m_drawFlags = b2DebugDraw.e_shapeBit;
            m_world.SetDebugDraw(dbgDraw);
            
            // walls for Box2D
            createPolygon(stage.stageWidth / 2 / SCALE, 1.0, 354, 1.1, 0.1);
            createPolygon(stage.stageWidth / 4 / SCALE, 2.1, 20, 1.2, 0.1);
            createPolygon(stage.stageWidth / 2 / SCALE, 3.2, 354, 1.1, 0.1);
            createPolygon(stage.stageWidth / 4 / SCALE, 4.0, 12, 2.3, 0.1);
            createPolygon(0.5, 5.1, 0, 6, 0.5);
            createPolygon(0, stage.stageHeight / 2 / SCALE, 90, stage.stageHeight / 2 / SCALE, 0.1);
            createPolygon(3.32, stage.stageHeight / 2 / SCALE, 90, 1.5, 0.1);
            createPolygon(4.58, stage.stageHeight / 2 / SCALE, 90, stage.stageHeight / SCALE, 0.1);
            
            // walls for PV3D
            addCubeAtPv3dWorldNoSave(stage.stageWidth / 2 / SCALE, 1.0, 354, 1.1, 0.1);
            addCubeAtPv3dWorldNoSave(stage.stageWidth / 4 / SCALE, 2.1, 20, 1.2, 0.1);
            addCubeAtPv3dWorldNoSave(stage.stageWidth / 2 / SCALE, 3.2, 354, 1.1, 0.1);
            addCubeAtPv3dWorldNoSave(stage.stageWidth / 4 / SCALE, 4.0, 12, 2.3, 0.1);
            addCubeAtPv3dWorldNoSave(0.5, 5.1, 0, 6, 0.5);
            addCubeAtPv3dWorldNoSave(0, stage.stageHeight / 2 / SCALE, 90, stage.stageHeight / 2 / SCALE, 0.1);
            addCubeAtPv3dWorldNoSave(3.32, stage.stageHeight / 2 / SCALE, 90, 1.5, 0.1);
            addCubeAtPv3dWorldNoSave(4.58, stage.stageHeight / 2 / SCALE, 90, stage.stageHeight / SCALE, 0.1);
            
            
            // elevator
            for (var i:int = 0; i < 14; i++)
            {
                addCubeAtPv3dWorld(0.23, 0.1, true);
                if (i % 2) addRectAtBox2dWorld(3.7, i * 0.4, 0, 0.23, 0.1, "elevator");
                else       addRectAtBox2dWorld(4.2, i * 0.4, 0, 0.23, 0.1, "elevator");
            }
            
            // balls
            for (i = 0; i < 4; i++)
            {
                addSphereAtPv3dWorld(40, 30, OBJ_SIZE);
                addCircleAtBox2dWorld(40, 30, OBJ_SIZE);
            }
        }
        
        private function addCubeAtPv3dWorldNoSave(posX:Number, posY:Number, degree:Number, hx:Number, hy:Number, id:String = "", density:Number = 0.0, restitution:Number = 0.0,
                                     setMass:Boolean = false):void
        {
            var obj3d:DisplayObject3D = scene.addChild(
                new Cube(
                    new MaterialsList( { all: mat } ),
                    hx * m_physScale * 2, 
                    30, 
                    hy * m_physScale * 2));
            
            obj3d.x = + posX * m_physScale - worldWidth / 2;
            obj3d.y = - posY * m_physScale + worldHeight / 2;
            obj3d.rotationZ = - degree
        }
        
        /**
         * AddItem at Papervision3D World
         */
        private function addSphereAtPv3dWorld(posX:Number, posY:Number, radius:Number):void
        {
            var obj3d:DisplayObject3D = scene.addChild(new Sphere(ballMat, radius / 2, 6, 5));
            pv3dObjsArr.push(obj3d);
        }
        
        /**
         * AddItem at Papervision3D World
         */
        private function addCubeAtPv3dWorld(hx:Number, hy:Number, isSaveArray:Boolean):void
        {
            var obj3d:DisplayObject3D = scene.addChild(
                new Cube(
                    new MaterialsList( { all: mat } ),
                    hx * m_physScale * 2, 
                    hy * m_physScale * 2, 
                    10));
            if(isSaveArray) pv3dObjsArr.push(obj3d);
        }
        
        /**
         * AddItem at Box2D World
         */
        private function addCircleAtBox2dWorld(posX:Number, posY:Number, radius:Number):void
        {
            var obj3d:DisplayObject3D = pv3dObjsArr[pv3dObjsArr.length - 1];
                
            var circleShape:b2CircleDef = new b2CircleDef();
            circleShape.radius = radius / m_physScale / 2;
            circleShape.density = 1;
            circleShape.friction = 1;
            circleShape.restitution = 0.6;
            var bodyDef:b2BodyDef = new b2BodyDef();
            bodyDef.position.Set((posX + worldWidth / 2) / m_physScale, (posY + worldHeight / 2) / m_physScale);
            bodyDef.userData = { id:"", obj:obj3d };
            var body:b2Body = m_world.CreateBody(bodyDef);
            body.CreateShape(circleShape);
            //body.SetUserData( { obj:obj3d } );
            body.SetMassFromShapes();
            
            box3dSpapesArr.push(body);
        }
        
        /**
         * AddItem at Box2D World
         */
        private function addRectAtBox2dWorld(
            posX:Number, posY:Number, degree:Number, 
            hx:Number, hy:Number, id:String = "", 
            density:Number = 0.0, restitution:Number = 0.0,
            setMass:Boolean = false):void
        {
            var obj3d:DisplayObject3D = pv3dObjsArr[pv3dObjsArr.length - 1];
            
            var bodyDef:b2BodyDef = new b2BodyDef();
            bodyDef.position.Set(posX, posY);
            bodyDef.angle = degree * Math.PI / 180;
            if (id) bodyDef.userData = { id:id, obj:obj3d };
            
            var blockShape:b2PolygonDef = new b2PolygonDef();
            blockShape.SetAsBox(hx, hy);
            blockShape.density = density;
            blockShape.restitution = restitution;
            
            var body:b2Body = m_world.CreateBody(bodyDef);
            body.CreateShape(blockShape);
            //body.SetUserData(obj3d);
            
            if (setMass) body.SetMassFromShapes();
        }
        
        /**
         * Enter Frame
         * @param    event
         */
        private function enterFrameHandler(event:Event):void
        {
            // update Box2D step
            m_world.Step(m_timeStep, m_iterations);
            // sync position to PV3D from Box2D
            for (var bb:b2Body = m_world.GetBodyList(); bb; bb = bb.GetNext())
            {
                if (bb.m_userData)
                {
                    if (bb.m_userData.id == "elevator")
                    {
                        bb.SetXForm(new b2Vec2(bb.GetPosition().x, bb.GetPosition().y - 0.02), 0);
                        if (bb.GetPosition().y < -0.1) bb.SetXForm(new b2Vec2(bb.GetPosition().x, stage.stageHeight / SCALE + 1), 0);
                        if (bb.GetPosition().y < 0.8) bb.SetXForm(bb.GetPosition(), bb.GetAngle() - 0.2);
                    }
                    
                    if (bb.m_userData.obj is DisplayObject3D)
                    {
                        var obj:DisplayObject3D = bb.m_userData.obj;
                        
                        obj.x = bb.GetPosition().x * m_physScale - worldWidth / 2;
                        obj.y = -bb.GetPosition().y * m_physScale + worldHeight / 2;
                        obj.rotationZ = -bb.GetAngle() * (180 / Math.PI);
                    }
                }
            }
            
            // Mouse Interactive
            easePitch += (cameraPitch - easePitch) * 0.2
            easeYaw += (cameraYaw - easeYaw) * 0.2
            camera.orbit(easePitch, easeYaw, true, cameraTarget);
            
            camera.zoom += (easeZoom - camera.zoom) * 0.1;
            
            singleRender();
        }
        
        
        private function createBackGround():void
        {
            graphics.beginFill(0xFFFFFF);
            graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
        }
        
        //-------------------------------------------------------------------
        // forked from Box2Dの練習
        // http://wonderfl.kayac.com/code/5fdd0af34ca9e7a3369f74c52cca9ddb85d136e4
        //-------------------------------------------------------------------
        
        private const SCALE:uint = 100;
        
        private function createPolygon(posX:Number, posY:Number, degree:Number, hx:Number, hy:Number, id:String = "", density:Number = 0.0, restitution:Number = 0.0,
                                     setMass:Boolean = false):void
        {
            var blockBodyDef:b2BodyDef = new b2BodyDef();
            blockBodyDef.position.Set(posX, posY);
            blockBodyDef.angle = degree * Math.PI / 180;
            if (id)
            {
                blockBodyDef.userData = new Object();
                blockBodyDef.userData.id = id;
            }
            
            var blockShape:b2PolygonDef = new b2PolygonDef();
            blockShape.SetAsBox(hx, hy);
            blockShape.density = density;
            blockShape.restitution = restitution;
            
            var blockBody:b2Body = m_world.CreateBody(blockBodyDef);
            blockBody.CreateShape(blockShape);
            
            if (setMass) blockBody.SetMassFromShapes();
        }
        
        
        
        // ----------------------------------------------
        // Mouse Interactive
        // http://wonderfl.kayac.com/code/2af71dd58ee46ba3ebf7496c63b4726c84a20980
        // ----------------------------------------------
        
        private var isOribiting:Boolean;
        private var cameraPitch:Number = 90;
        private var cameraYaw:Number = 270;
        private var cameraTarget:DisplayObject3D = DisplayObject3D.ZERO;
        private var previousMouseX:Number;
        private var previousMouseY:Number;
        private var easePitch:Number = 90;
        private var easeYaw:Number = 270;
        private var easeZoom:Number = 100;
        private var ballMat:FlatShadeMaterial;
        
        private function onMouseDown(event:MouseEvent):void
        {
            isOribiting = true;
            previousMouseX = event.stageX;
            previousMouseY = event.stageY;
            singleRender();
        }
 
        private function onMouseUp(event:MouseEvent):void
        {
            isOribiting = false;
        }
 
        private function onMouseMove(event:MouseEvent):void
        {
            var differenceX:Number = event.stageX - previousMouseX;
            var differenceY:Number = event.stageY - previousMouseY;
 
            if(isOribiting)
            {
                cameraPitch += differenceY * 0.25;
                cameraYaw += differenceX * 0.25;
 
                cameraPitch %= 360;
 
                cameraPitch = cameraPitch > 0 ? cameraPitch : 0.0001;
                cameraPitch = cameraPitch < 180 ? cameraPitch : 179.9999;
 
                previousMouseX = event.stageX;
                previousMouseY = event.stageY;
            }
        }
        
        private function onMouseWheel(e:MouseEvent):void 
        {
            easeZoom += e.delta;
            easeZoom = Math.max(1, easeZoom);
        }
    }
}