Beautifl - Flash Gallery

Thumbnail : [Box2D] ピタゴラスイッチみたいなことがしたかった 反省はしている
[Box2D] ピタゴラスイッチみたいなことがしたかった 反省はしている
enoeno 2009-08-28 All rights reserved

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

/*

初めてさわった滑車ジョイントがわからなすぎて、悪戦苦闘でした

ときどきボールが壁をすり抜けます
どきどき通路がボールで詰まります

[ 機能 ] 
・スライダーを移動させるとボールの量が変えられます
・

[ 参考にさせていただいたサイト ]
http://plug.heteml.jp/motulog/2008/10/box2dflashas3201-2.html#more
http://hokori.net/category/note/
http://www.at-sonic.com/blog/index.php?page=5
http://www.kyucon.com/doc/box2d/Box2D/Dynamics/Joints/b2PulleyJoint.html#methodSummary

*/ 
package  {
    import Box2D.Collision.b2AABB;
    import Box2D.Collision.Shapes.*;
    import Box2D.Common.Math.b2Vec2;
    import Box2D.Dynamics.b2Body;
    import Box2D.Dynamics.b2BodyDef;
    import Box2D.Dynamics.b2DebugDraw;
    import Box2D.Dynamics.b2World;
    import Box2D.Dynamics.Joints.*; 
    
    
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Rectangle;
    
    import flash.display.StageScaleMode;
    import flash.display.StageAlign;
    import flash.display.StageQuality;
    import flash.events.TimerEvent;
    import flash.utils.Timer;
    import flash.utils.getTimer;
    
    
    public class windmill extends Sprite {
        private var world:b2World;
        private const SCALE:int = 100;
        
        private var m_sprite:Sprite;
        private var colors:Array;
        
        private var ADD_INTERVAL_TIME:int = 525;
        private var myTimer:Timer;
        
        public function windmill():void {

            stage.quality = StageQuality.BEST;
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            
            init();
        }
        
       private function init():void {
           
           //物理エンジン初期化
           createWorld();
           //風車作成( 半径, x座標, y座標, 分割数(かごの数));
           createWindmill( 40, 100, 80, 6);
           //壁作成
           createWall();
           //滑車作成
           createPulley();
           //スライダー作成
           createSlider();
           
           //シミュレーションスタート
           start();

       }
       
       //物理エンジン初期化
       private function createWorld():void {
           var worldAABB:b2AABB = new b2AABB();
           worldAABB.lowerBound.Set(-100.0, -100.0);
           worldAABB.upperBound.Set(100.0, 100.0);
           
           var doSleep:Boolean = true;
           
           // 重力を定義する
           var gravity:b2Vec2 = new b2Vec2(0.0, 10.0);
    
            // 世界のインスタンスを作成する
            world = new b2World( worldAABB, gravity, doSleep );
            
            m_sprite = new Sprite();
            addChild(m_sprite);
            debugMode();
           
       }
       
       //デバッグ
       private function debugMode():void {
           var debugDraw:b2DebugDraw = new b2DebugDraw();
           debugDraw.m_sprite = this;
           debugDraw.m_drawScale = SCALE; // 1mを100ピクセルにする
           debugDraw.m_fillAlpha = 0.8; // 不透明度
           debugDraw.m_lineThickness = 1; // 線の太さ
           //debugDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit | b2DebugDraw.e_centerOfMassBit;
           debugDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit;
           
           world.SetDebugDraw(debugDraw);
       }
       
       //風車作成
       private function createWindmill( radius:int, xpos:Number, ypos:Number, segment:int ):void {
           
           //風車の車体?を作成
           var bodyDef:b2BodyDef = new b2BodyDef();
           bodyDef.position.Set( xpos/SCALE, ypos/SCALE);
           bodyDef.angle = 0;
           
           
           var cdef:b2CircleDef= new b2CircleDef();
           cdef.radius = radius/SCALE;    // 半径
           cdef.density = 0.5;                 // 密度:0だと動かない
           cdef.friction = 0.0;                // 摩擦:大きいと滑りにくい
           cdef.restitution = 1;              // 反発:大きいと反発しにくい
           
           
           // 物体を作る
           var b2_Body:b2Body = world.CreateBody( bodyDef );
           
           // 形を物体に追加する
           b2_Body.CreateShape( cdef );
           
           // 動く物体として作る
           b2_Body.SetMassFromShapes();
           
           
           
           //風車を回転させる基点を作成
           var baseBodyDef:b2BodyDef = new b2BodyDef();
           baseBodyDef.position.Set( xpos/SCALE, ypos/SCALE);
           
           var bcdef:b2CircleDef = new b2CircleDef();
           bcdef.radius = 0.1;        // 半径
           bcdef.density = 0.5;      // 密度:0だと動かない
           bcdef.friction = 0.0;        // 摩擦:大きいと滑りにくい
           bcdef.restitution = 1;    // 反発:大きいと反発しにくい
           
           
           // 物体を作る
           var b2_BaseBody:b2Body = world.CreateBody( baseBodyDef );
           
           // 形を物体に追加する
           b2_BaseBody.CreateShape( bcdef );
           
           

            // 風車とワールドを固定するジョイントの定義   
            var jointDef:b2RevoluteJointDef = new b2RevoluteJointDef();
            jointDef.enableLimit = false;
            /*
            jointDef.enableMotor = true;
            jointDef.motorSpeed = 0;
            jointDef.maxMotorTorque = 100000;
            */
            
            
            var anchor:b2Vec2 = new b2Vec2( xpos/SCALE, ypos/SCALE);
            //var anchor = new b2Vec2(1.98, 2.7);
            jointDef.Initialize( b2_Body, b2_BaseBody, anchor );
            //(rev_joint, rev_box, new b2Vec2(13, 6.5));
            var revolute_joint : b2RevoluteJoint = world.CreateJoint( jointDef ) as b2RevoluteJoint;
            

            
            //風車のかごを作成してジョイントで風車に固定する
            for( var i:int=0; i < segment; i++){
                var angle:Number = 360/segment*i;
                var rad:Number = angle * Math.PI/180;
                //trace( "angle : "+angle );
                //trace( "rad : "+rad );
                
                var x:Number = radius*Math.cos(rad)+xpos;
                var y:Number = radius*Math.sin(rad)+ypos;
                //trace("x : "+x);
                //trace("y : "+y);
                //trace("----------");
                
                
                
                var boxBodyDef:b2BodyDef = new b2BodyDef();
                boxBodyDef.position.Set(x/SCALE, y/SCALE);
                //boxBodyDef.position.Set(0,0);
                boxBodyDef.angle = rad;
                
                // 物体を作る
                 var boxBody:b2Body = world.CreateBody( boxBodyDef );
               
               
    
                var boxShapeDef:b2PolygonDef= new b2PolygonDef();
                boxShapeDef.density = 6;             // 密度 
                boxShapeDef.restitution = 0.01;  // 反発係数
    
                boxShapeDef.vertexCount = 4;
                
                boxShapeDef.vertices[0].Set( 0.30,        0.00 );
                boxShapeDef.vertices[1].Set( 0.30,        0.30 );
                boxShapeDef.vertices[2].Set( 0.25,        0.30 );
                boxShapeDef.vertices[3].Set( 0.25,        0.00 );
                
                // 形を物体に追加する
                boxBody.CreateShape( boxShapeDef );
                
                /**/
                // 定義を変更してもう1個の形を追加する
                boxShapeDef.vertexCount = 4;
                boxShapeDef.vertices[0].Set( 0.00,        0.00 );
                boxShapeDef.vertices[1].Set( 0.30,        0.00 );
                boxShapeDef.vertices[2].Set( 0.30,        0.07 );
                boxShapeDef.vertices[3].Set( 0.00,        0.07 );
                
                
                // 形を物体に追加する
                boxBody.CreateShape( boxShapeDef );
                
                //
                boxBody.SetMassFromShapes();
                
                
                
                // ジョイントの定義   
                var pinJointDef : b2RevoluteJointDef = new b2RevoluteJointDef();
                
                
                // joint 
                pinJointDef.Initialize( boxBody, b2_Body, new b2Vec2(x/SCALE, y/SCALE)); 
                //pinJointDef.collideConnected = true;
                pinJointDef.enableLimit = true
                pinJointDef.lowerAngle = 0*Math.PI/180;
                pinJointDef.upperAngle = 0*Math.PI/180;
                var distance_joint : b2RevoluteJoint = world.CreateJoint( pinJointDef ) as b2RevoluteJoint;
                
            }

       }
       
       private function createBasket():void {
           
           
       }
       
      
       //壁作成
       private function createWall():void {
           var wxArr:Array    = [ 173,    280,    225,    280,    352,    stage.stageWidth,        385,    352,    385    ];    //x座標
           var wyArr:Array    = [ 240,    190,    352,    415,    360,    0,                                395,    430,    460    ];    //y座標
           var wwArr:Array    = [ 100,    5,        5,        5,        150,    5,                                150,    150,    150    ];    //幅
           var whArr:Array    = [ 5,        250,    225,    120,    5,        stage.stageHeight*2,    5,        5,        5        ];    //高さ
           var rArr:Array        = [ 20,    0,        0,        0,        30,    0,                                -15,    15    ,    -15    ];    //角度(傾き)
            
            /* make wall */
            for (var i:int = 0; i < wxArr.length; i++) {
                var wallBodyDef:b2BodyDef = new b2BodyDef();
                wallBodyDef.position.Set(wxArr[i] /SCALE, wyArr[i] /SCALE);
                
                var wallShapeDef:b2PolygonDef = new b2PolygonDef();
                wallShapeDef.restitution = 0.01;  // 反発係数
                wallShapeDef.friction = 0.0;
                wallShapeDef.SetAsOrientedBox( wwArr[i] / 2 / SCALE, whArr[i]/2 / SCALE, new b2Vec2(0,0), rArr[i]/180/Math.PI );
                
                var wallBody:b2Body = world.CreateBody( wallBodyDef );
                wallBody.CreateShape( wallShapeDef );
            }
           
       }
       
       //滑車作成
       private function createPulley():void {
           var jd:b2PulleyJointDef = new b2PulleyJointDef();
           
           //bodyDef
           var bd1:b2BodyDef = new b2BodyDef();
           bd1.position.Set(250 / SCALE, 200 / SCALE);
           
           
           var bd2:b2BodyDef = new b2BodyDef();
           bd2.position.Set(400 / SCALE, 250 / SCALE);


            //body
           var body1:b2Body = world.CreateBody( bd1);
           
           
           //box
            var box1:b2PolygonDef = new b2PolygonDef();
            box1.density = 0.5;                // 密度:0だと動かない
            box1.friction = 0.5;                // 摩擦:大きいと滑りにくい
            box1.restitution = 0.1;            // 反発:大きいと反発しにくい
            
            /**/
            box1.vertexCount = 4;
            
            box1.vertices[0].Set( -0.25,        0.00 );
            box1.vertices[1].Set( 0.25,        0.00 );
            box1.vertices[2].Set( 0.25,        0.05 );
            box1.vertices[3].Set( -0.25,        0.05 );
            
            
            // 形を物体に追加する
            body1.CreateShape( box1 );
            
            
            /**/
            box1.vertexCount = 4;
            
            box1.vertices[0].Set( 0.20,        0.00 );
            box1.vertices[1].Set( 0.25,        0.00 );
            box1.vertices[2].Set( 0.25,        0.75 );
            box1.vertices[3].Set( 0.20,        0.75 );

            // 形を物体に追加する
            body1.CreateShape( box1 );
            
            
            
            box1.vertexCount = 4;
            
            box1.vertices[0].Set( -0.20,        0.30 );
            box1.vertices[1].Set( -0.20,        0.75 );
            box1.vertices[2].Set( -0.25,        0.75 );
            box1.vertices[3].Set( -0.25,        0.30 );

            // 形を物体に追加する
            body1.CreateShape( box1 );
            
            /**/
            box1.vertexCount = 4;
            // 形を物体に追加する
            
            box1.vertices[0].Set( 0.25,        0.95 );
            box1.vertices[1].Set( 0.25,        1.05 );
            box1.vertices[2].Set( -0.25,        0.80 );
            box1.vertices[3].Set( -0.25,        0.70 );

            body1.CreateShape( box1 );
            
            
            box1.vertexCount = 4;
            
            box1.vertices[0].Set( -0.25,        0.00 );
            box1.vertices[1].Set( -0.25,        -0.50 );
            box1.vertices[2].Set( -0.20,        -0.50 );
            box1.vertices[3].Set( -0.20,        0.00 );
            
            
            // 形を物体に追加する
            body1.CreateShape( box1 );
           body1.SetMassFromShapes();
            
            
            //同じ質量のボックスでないと釣り合いが取れないっぽい…?
            //body
           var body2:b2Body = world.CreateBody( bd2);
           
           
           //box1よりすこしだけ密度を上げる→重くする
           //box
            var box2:b2PolygonDef = new b2PolygonDef();
            box2.density = 0.6;                // 密度:0だと動かない
            box2.friction = 0.5;                // 摩擦:大きいと滑りにくい
            box2.restitution = 0.1;            // 反発:大きいと反発しにくい


            // 形を物体に追加する
            box2.SetAsBox(20 / SCALE, 20 / SCALE);

            
            
            // 形を物体に追加する
            body2.CreateShape( box2 );
            body2.SetMassFromShapes();
            
            
            
            
            
            
            //joint
            var ground1:b2Vec2 = new b2Vec2(250 /SCALE, 10 /SCALE);
            var ground2:b2Vec2 = new b2Vec2(400 /SCALE, 10 /SCALE);
            var anchor1:b2Vec2 = bd1.position;
            var anchor2:b2Vec2 = bd2.position;
            var ratio:Number = 1;
            jd.Initialize(body1, body2, ground1, ground2, anchor1, anchor2, ratio);
            
            world.CreateJoint(jd);

       }
       
      //ボール追加
      private function addBall(e:Event):void{

            var    circleDef:b2CircleDef = new b2CircleDef();
            var    crad:Number = 0.075;
            //var    crad = 0.030 + Math.random()/10;
            //trace(crad);
                    //circleDef.radius = Math.random()/10+0.00075;
                    circleDef.radius = crad;
                    circleDef.density = 5.0;
                    circleDef.friction = 0.5;
                    circleDef.restitution = 0.5;
                
                
            var    circleBD:b2BodyDef = new b2BodyDef();
                    //circleBD.position.Set(1.8, 0);
                    circleBD.position.Set(0.35, 0);
                    //circleBD.position.Set(1.7, 1.7);
                    
            // 実際の円を生成
           var        sp:Sprite = new Sprite;
                       sp.graphics.beginFill( getColor(), 0.8);
                       sp.graphics.drawCircle(0, 0, 30);
                       sp.graphics.endFill();
                    //一時的に画面外へ
                    sp.x = -crad*SCALE*2;
                    sp.y = -crad*SCALE*2;
        
           // 円を保存
                       circleBD.userData = sp;
                       circleBD.userData.width = crad*SCALE*2;
                       circleBD.userData.height = crad*SCALE*2;
                      m_sprite.addChild(circleBD.userData);
            
                    
           
           var        circleBody:b2Body = world.CreateBody( circleBD );
                       circleBody.CreateShape( circleDef );
                    circleBody.SetMassFromShapes();    

        }//end of function
        
        //配列に登録したランダムな色を返す
        private function getColor():Number {
            var colors:Array = [ 0xdffe24, 0x84d90a, 0x2a95bf, 0xf2b910, 0xff368c, 0x6cbace];
            return  colors[ Math.floor(Math.random()*colors.length) ];
        }//end of function
        
        //シミュレーションスタート
        private function start():void {
           addEventListener(Event.ENTER_FRAME, enterFrameHandler);
           myTimer = new Timer(ADD_INTERVAL_TIME, 0);
           myTimer.addEventListener(TimerEvent.TIMER, addBall);
           myTimer.start();
         }//end of function
        
        private function enterFrameHandler(event:Event):void {
            // 物理シミュレーションを進める
            world.Step(1 / 24, 10);
            
            if (world == null) {
                return;
            }
            
            
            for (var bb:b2Body = world.m_bodyList; bb; bb = bb.m_next){
                /**/
                if (bb.m_userData is Sprite){
                    bb.m_userData.x = bb.GetPosition().x * SCALE;
                    bb.m_userData.y = bb.GetPosition().y * SCALE;
                    bb.m_userData.rotation = bb.GetAngle() * (180/Math.PI);
                }
                
                //trace(bb.GetPosition().y*SCALE);
                if( bb.GetPosition().y*SCALE > stage.stageHeight ){
                    //trace("delete : "+bb);
                    world.DestroyBody( bb );
                    m_sprite.removeChild( bb.m_userData );
                }
                
            }
            
            //trace("-----");
            
        }
        
        
        /*------スライダー関係
        */
        
        private var bar:Sprite = new Sprite;
        private var point:Sprite = new Sprite;
        private function createSlider():void {
            
            bar.graphics.beginFill( 0xcccccc, 1.0 );
            bar.graphics.drawRect( 0, 0, 150, 5 );
            bar.graphics.endFill();
            
            
            point.graphics.beginFill( 0xFF0000, 1.0);
               point.graphics.drawRect(0, 0, 10, 10);
               point.graphics.endFill();
            
            bar.addChild( point );
            addChild( bar );
            
            bar.x = 10;
            bar.y = 400;
            
            point.x = bar.width/2 - point.width/2;
            point.y = -2;
            point.buttonMode = true;
            point.addEventListener( MouseEvent.MOUSE_DOWN, startMove );
        }
        
        private function startMove(e:Event):void {
            
            stage.addEventListener( MouseEvent.MOUSE_UP, stopMove );
            stage.addEventListener( MouseEvent.MOUSE_UP, updateIntervalTime );
            point.startDrag( true,new Rectangle( 0, -2, bar.width - point.width,0) );
            point.alpha = 0.8;
            
            point.addEventListener( MouseEvent.MOUSE_MOVE, updateIntervalTime );
        }
        
        private function stopMove( e:Event ):void {
            point.stopDrag();
            point.alpha = 1.0;
        }
        
        private function updateIntervalTime( e:Event ):void {
            var def:Number = point.x - bar.width/2;
            ADD_INTERVAL_TIME = 525 + def*6;
            
            myTimer.reset();
            myTimer.removeEventListener(TimerEvent.TIMER, addBall);
            

            myTimer = new Timer(ADD_INTERVAL_TIME, 0);
            myTimer.addEventListener(TimerEvent.TIMER, addBall);
            myTimer.start();
            //trace(ADD_INTERVAL_TIME);
        }

    }
}