Beautifl - Flash Gallery

Thumbnail : flash on 2009-6-5
flash on 2009-6-5
hacker_n2ylj3ym 2009-08-28 MIT License

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

 
package  {
    import Box2D.Collision.Shapes.*;
    import Box2D.Collision.b2AABB;
    import Box2D.Common.Math.b2Vec2;
    import Box2D.Dynamics.Joints.*;
    import Box2D.Dynamics.b2Body;
    import Box2D.Dynamics.b2BodyDef;
    import Box2D.Dynamics.b2DebugDraw;
    import Box2D.Dynamics.b2World;
    
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.events.TimerEvent;
    import flash.text.TextField;
    import flash.utils.Timer;

    
    public class Box2DGame2 extends Sprite {
        private var world:b2World;
        private var joint1:b2RevoluteJoint;
    private var joint2:b2RevoluteJoint;
        private var textfield:TextField;    
        private var payTextfield:TextField;
        private var coinTextfield:TextField;
        private var money:int = 30;
        private var payMoney:int = 0;
        private var floorList:Array;
        
        private static const DRAW_SCALE:Number = 100;
        
        public function Box2DGame2():void {
            init();
            addEventListener(Event.ENTER_FRAME, enterFrameHandler);
      
            textfield = new TextField();
            this.addChild(textfield);
        }
        
        public function init():void {
            initWorld();
      initWall();
      initBar();
      initPin();
      initFloor();
      initButton();
        }
        
                
        /**
         * world設定
         */
        private function initWorld():void {
            // 外枠を定義する
            var worldAABB:b2AABB = new b2AABB();
            worldAABB.lowerBound.Set(-100, -100);
            worldAABB.upperBound.Set(100, 100);
            
            // 重力加速度
            var gravity:b2Vec2 = new b2Vec2(0, 10);
            
            // 外枠と重力を指定して、物理エンジン全体をセットアップする
            world = new b2World(worldAABB, gravity, true);
            
            // 描画設定
            var debugDraw:b2DebugDraw = new b2DebugDraw();
            debugDraw.m_sprite = this;
            debugDraw.m_drawScale = DRAW_SCALE; // 1mを100ピクセルにする
            debugDraw.m_fillAlpha = 1; // 不透明度
            debugDraw.m_lineThickness = 1; // 線の太さ
            debugDraw.m_drawFlags = b2DebugDraw.e_shapeBit;
            world.SetDebugDraw(debugDraw);
        }
        
    /**
     * ジョイントバーの設置
     */
        private function initBar():void {
          joint1 = createJointBar(1.23, 0);
      joint2 = createJointBar(1.67, 0);
        }
        private function createJointBar(x:Number, y:Number):b2RevoluteJoint {
          // 動くバーの支点となるオブジェクト
      var point:b2Body = createBox(0.01, 0.01, x, y, 0, true);
      
      // 動くバー
      var bar:b2Body = createBox(0.02, 0.4, x, y + 0.4);
      
      // 回転ジョイントの設定
      var jointDef:b2RevoluteJointDef = new b2RevoluteJointDef();
      jointDef.enableMotor = true;
      jointDef.motorSpeed = 0; // ここで初期速度を設定すると、joint.SetMoterSpeed()の指定時におかしくなる?
      jointDef.maxMotorTorque = 300000; // 謎。 0だと動かない
      jointDef.Initialize(bar, point, point.GetPosition()); // pointにbarをくっつける
      var joint:b2RevoluteJoint = world.CreateJoint(jointDef) as b2RevoluteJoint;
      joint.SetMotorSpeed(1); // こっちで初期スピードの設定をする
      
      return joint;
        }
        
        
    /**
     * ピンの設置
     */
        private function initPin():void {
      for (var i:int = 0; i < 7; i++) {
        for (var j:int = 0; j < 10; j++) {
          if (i % 2 == 1 && j == 9) {
            continue;
          }
          var x:Number = j*0.3 + (i % 2 == 1 ? 0.15 : 0) + 0.05; 
          var y:Number = i*0.3 + 1.3;
//          createCircle(0.01, x, y, true);
          createBox(0.01, 0.01, x, y, Math.PI/4, true);
        }
      }
        }
        
        /**
         * 床の設置   消したり出したりする
         */
        private function initFloor():void {
      floorList = [];
      for (var j:int = 0; j < 10; j++) {
        var x:Number = j*0.3 + 0.05; 
        var y:Number = 6*0.3 + 1.3;
        
        // 横の壁
        createBox(0.01, 0.2, x, y + 0.2, 0, true);
        
        if (j < 9) {
          // こっちが床
          floorList.push(createBox(0.15, 0.01, x + 0.15, y + 0.4, 0, true));
        }
      }
        }
        
        /**
         * 壁の設置
         */
        private function initWall():void {
      createBox(0.05, 3, 3.1, 3, 0, true);
      createBox(0.05, 3, 4.2, 3, 0, true);
      createBox(1, 3, -1.25, 3, 0, true);
//      createBox(0.5, 0.6, 3.6, 3.5, 0, true);

      createBox(0.07, 0.07, 3.15, 0.8, Math.PI/4, true);
      createBox(0.07, 0.07, 3.15, 0.7*3 + 0.2, Math.PI/4, true);
      createBox(0.07, 0.07, 4.15, 0.6*2 + 0.2, Math.PI/4, true); 
      createBox(0.01, 0.01, 3.65 , 0.8*0.5, Math.PI/4, true);
      createBox(0.01, 0.01, 3.65 , 0.8*1.5, Math.PI/4, true);
      createBox(0.01, 0.01, 3.65 , 0.8*2.5, Math.PI/4, true);
      createBox(0.01, 0.01, 3.65 , 0.8*3.5, Math.PI/4, true);
      
        }
        
        /**
         * ボタン作成
         */
    private function initButton():void {
      // コイン投入ボタン
      var button:Sprite = new Sprite();
      button.graphics.beginFill(0xFFFFFF);
      button.graphics.drawRoundRectComplex(320, 300, 80, 30, 5, 5, 5, 5);
      button.graphics.endFill();
      button.buttonMode = true;
      button.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
      coinTextfield = new TextField();
      coinTextfield.text = '投入: 残' + money+'枚';
      coinTextfield.selectable = false;
      coinTextfield.x = 325;
      coinTextfield.y = 305;
      button.addChild(coinTextfield);
      addChild(button);
      
      // 払い出しボタン
      var buttonPay:Sprite = new Sprite();
      buttonPay.graphics.beginFill(0xFFFFFF);
      buttonPay.graphics.drawRoundRectComplex(320, 340, 80, 30, 5, 5, 5, 5);
      buttonPay.graphics.endFill();
      buttonPay.buttonMode = true;
      buttonPay.addEventListener(MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void {
        if (payMoney) {
          var timer:Timer = new Timer(150, payMoney);
          timer.addEventListener(TimerEvent.TIMER, function (et:TimerEvent):void {
            createCircle(0.12, Math.random()*0.5 + 3.3, -1);
          });
          timer.addEventListener(TimerEvent.TIMER_COMPLETE, function(et:TimerEvent):void {
            timer.stop();
          });
          timer.start();
          payMoney = 0;
          dropCoins();
        }
      });
      payTextfield = new TextField();
      payTextfield.selectable = false;
      payTextfield.text = '払戻: 0枚';
      payTextfield.x = 330;
      payTextfield.y = 345;
      buttonPay.addChild(payTextfield);
      addChild(buttonPay);
    }
    

    /**
     * クリック時の処理
     */
    private function onMouseDown(event:MouseEvent):void {
      // クリックされた場所に何か落とす
      if (money > 0) {
        var circle:b2Body = createCircle(0.12, 1.5, -1);
        circle.m_userData.name = 'ball';
        money--;
        coinTextfield.text = '投入: 残' + money.toString() +'枚';
      }
    }
        
        /**
         * フレームごとの更新処理
         */
        private function update():void {
          // バーを左右に振る
      var angle:int = joint1.GetJointAngle() / Math.PI * 180;
      if (angle < -50) {
        joint1.SetMotorSpeed(0.8);
      } else if (50 < angle) {
        joint1.SetMotorSpeed(-0.8);
      }
      
      // 2つめのバーは1つ目のバーと同じ動きをさせる 
      joint2.SetMotorSpeed(joint1.GetMotorSpeed());

      var check_list:Array = new Array(9);
      var hit_list:Array = new Array(9);
      for (var i:int = 0; i < hit_list.length; i++) {
        hit_list[i] = 0;
      }

      // spriteを描画しつつ点数の計算も行う     処理がすごく怪しい
      for (var b:b2Body = world.GetBodyList(); b; b = b.GetNext()) {
        // 物体の位置を更新する処理。中身は後述
        if (!b.m_userData || !(b.m_userData as Object).hasOwnProperty('sprite')) {
          continue;
        }
        
        try {
          if ((b.m_userData as Object).hasOwnProperty('sprite')) {
            var sprite:Sprite = b.m_userData.sprite as Sprite;
            sprite.x = b.GetWorldCenter().x * DRAW_SCALE;
            sprite.y = b.GetWorldCenter().y * DRAW_SCALE;
            sprite.rotation = b.GetAngle() * 180 / Math.PI;
    
            // 終了判定  
            for (var j:int = 0; j < 9; j++) {
              var x:Number = j*0.3 + 0.05 + 0.15; 
              var y:Number = 6*0.3 + 1.3 + 0.35; 
              
              // 床に落ちた下のコイン
              if (sprite.hitTestPoint(x * DRAW_SCALE, y * DRAW_SCALE)) {
                hit_list[j] = 1;
                if (check_list[j] == 1) {
                  dropCoins();
                }
              }
              
              // 床に重なったコインの上のコイン
              if (sprite.hitTestPoint(x * DRAW_SCALE, (y - 0.35) * DRAW_SCALE)) {
                check_list[j] = 1;
              }
            }
          }
        } catch (e:Error) {
        }
      }                  
        
      calculatePayment(hit_list);
        }
        
        /**
         * 払い戻し枚数の計算
         * 2枚隣合っていたら4枚、3枚隣り合っていたら8枚,4枚隣り合っていたら16枚・・・
         */
        private function calculatePayment(hit_list:Array):void {
          payMoney = 0;

          var result:String = hit_list.join('');
          hit_list = null;
          result = result.replace(/0+/g, '0');
          var list:Array = result.split('0');
          
          for (var i:int = 0; i < list.length; i++) {
            var value:String = list[i]; 
            if (value.length > 1) {
              payMoney += Math.pow(2, value.length);
            }
          }
      payTextfield.text = "払戻: " + payMoney.toString() + "枚";
        }
        
        /**
         * 床を消してコインを全部落とす
         */
        private function dropCoins():void {
      for each (var floorBox:b2Body in floorList) {
        // world.DestroyBodyでb2bodyオブジェクトを削除
        world.DestroyBody(floorBox);
      }
      floorList = new Array();;
    
      // 1秒後に再構築
      var timer:Timer = new Timer(1000, 1);
      timer.addEventListener(TimerEvent.TIMER_COMPLETE, function(te:TimerEvent):void {
        initFloor();
        timer.stop();
      });
      timer.start();
        }
        


    /**
    * 毎フレーム呼び出される
    */    
        private function enterFrameHandler(event:Event):void {
            if (world == null) {
                return;
            }
             
            update();
            
            world.Step(1 / 48, 10);
        }
        
        
        
        //////////////////////////////////////////////////////////////////////////////////
    //                    ここから下はオブジェクト生成用メソッド
        //////////////////////////////////////////////////////////////////////////////////
    /**
     * 四角形を作成
     */
    private function createBox(width:Number, height:Number, x:Number, y:Number, angle:Number = 0, is_static:Boolean=false):b2Body {
      var boxBodyDef:b2BodyDef = new b2BodyDef();
      boxBodyDef.position.Set(x, y);
      
      var body:b2Body = world.CreateBody(boxBodyDef);
      body.CreateShape(createBoxShapeDef(width, height, angle, is_static));
      if (!is_static) {
        body.SetMassFromShapes();
      }
      body.m_userData = new Object();
      body.m_userData.name = 'box';
      
      return body;
    }
    
    /**
     * 円作成
     */
    private function createCircle(radius:Number, x:Number, y:Number, is_static:Boolean = false):b2Body {
      // 円の場所を設定する
      var bodyDef:b2BodyDef = new b2BodyDef();
      bodyDef.position.Set(x, y);
      
      // 円の大きさなどを設定する
      var shapeDef:b2CircleDef = new b2CircleDef();
      shapeDef.radius = radius;
      shapeDef.density = 1;     // 密度 [kg/m^2]
      shapeDef.restitution = 0.3;  // 反発係数、通常は0~1
      shapeDef.density = is_static ? 0 : 1;
      
      // 円を動く物体として作る
      var body:b2Body = world.CreateBody(bodyDef);
      body.CreateShape(shapeDef);
      if (!is_static) {
        body.SetMassFromShapes();
      }
      body.m_userData = new Object();
      body.m_userData.name = 'circle';
      body.m_userData.sprite = createCircleSprite(x, y, radius);
      this.addChild(body.m_userData.sprite);
      
      return body;
    }
    
    private function createCircleSprite(x:Number, y:Number, radius:Number):Sprite {
      var s:Sprite = new Sprite();
      s.graphics.beginFill(0x0000FF, 0);
      s.graphics.drawCircle(0, 0, radius * DRAW_SCALE);
      s.graphics.endFill();
      s.x = x * DRAW_SCALE;
      s.y = y * DRAW_SCALE;
      
      s.addEventListener(Event.ENTER_FRAME, function(e:Event):void {
        if (s.y >= 500) {
          s.parent.removeChild(s);
          if (315 <= s.x && s.x <= 405) {
            money++;
            coinTextfield.text = '投入: 残' + money.toString() +'枚';
          }
        }
      });
      
      return s; 
    }
    
    
    /**
     * 箱の形を設定
     */
    private function createBoxShapeDef(width:Number, height:Number, angle:Number = 0, is_static:Boolean = false):b2PolygonDef {
      var boxShapeDef:b2PolygonDef= new b2PolygonDef();
      if (angle) {
        // 傾いた物体 
        boxShapeDef.SetAsOrientedBox(width, height, new b2Vec2(0, 0), angle);
      } else {
        // まっすぐな物体
        boxShapeDef.SetAsBox(width, height);
      }
      boxShapeDef.density = is_static ? 0 : 1;
      boxShapeDef.restitution = 0.3;  // 反発係数、通常は0~1
      
      return boxShapeDef;
    }
    }
}