Math and (Quasi) Physics in Action Script 3

Box 2D - simulation of falling balls(2)

Simple demonstration of balls bouce on the floor.

Clicking on the empty space on the stage crates a new ball. Dragging a ball shows a line that connects the mouse cursor and the ball, which works like a rubber band.

Main.as

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 flash.display.Sprite;
  import flash.events.Event;
  import flash.events.MouseEvent;
  
  public class Main extends Sprite {
    private const DRAW_SCALE:uint = 100;
    private var world:b2World;
    private var fps:int;
    private var bDrag:Boolean = false;
    private var dTarget:b2Body;
    private var wallDef:Array = [[2.5, 0.48, 2, 0.05],
      [4.52, 2.5, 0.05, 2],
    [2.5, 4.52, 2, 0.05],
    [0.48, 2.5, 0.05, 2]
    ];
    private var circles:Array = [];
    private var lineStage:Sprite, ballStage:Sprite;
    public function Main():void {
      fps = stage.frameRate;
      stage.addEventListener(MouseEvent.MOUSE_DOWN, h_mouseDown);
      stage.addEventListener(MouseEvent.MOUSE_UP, h_mouseUp);
      addEventListener(Event.ENTER_FRAME, h_enterFrame);
      // background
      graphics.beginFill(0xAAAAAA);
      graphics.drawRect(0,0,500,500);
      graphics.endFill();
      graphics.beginFill(0xFFFFFF);
      graphics.drawRect(50,50,400,400);
      graphics.endFill();
      addChild(ballStage = new Sprite());
      addChild(lineStage = new Sprite());
      init();
    }
    
    private function init(event:MouseEvent = null):void {

      // create the world
      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,false);

      // create walls
      var wallBodyDef:b2BodyDef;
      var wallShapeDef:b2PolygonDef;
      var wall:b2Body;
      var i:uint;
      for (i = 0; i < wallDef.length; i ++) {
        wallBodyDef = new b2BodyDef();
        wallBodyDef.position.Set(wallDef[i][0],wallDef[i][1]);
        wallShapeDef = new b2PolygonDef();
        wallShapeDef.SetAsBox(wallDef[i][2],wallDef[i][3]);
        wall = world.CreateBody(wallBodyDef);
        wall.CreateShape(wallShapeDef);
      }
    }
    
    private function h_mouseDown(evt:MouseEvent):void {
      evt.stopImmediatePropagation();
      if (evt.target == stage) {
        createBall();
      } else {
        for (var i:uint = 0; i < circles.length; i ++) {
          if (circles[i].GetUserData() == evt.target) {
            bDrag = true;
            dTarget = circles[i];
          }
        }
      }
    }
    
    private function h_mouseUp(evt:MouseEvent):void {
      bDrag = false;
    }
    
    
    private function createBall():void {
      // create balls
      if (mouseX < 50 || mouseX > 450 || mouseY < 50 || mouseY > 450) {
        return;
      }
      
      var circleBodyDef:b2BodyDef;
      var circleShapeDef:b2CircleDef;
      var circleBody:b2Body;
      var circleSp:Sprite;
      circleBodyDef = new b2BodyDef();
      circleBodyDef.position.Set(mouseX / DRAW_SCALE, mouseY / DRAW_SCALE);
      circleShapeDef = new b2CircleDef();
      circleShapeDef.radius = 0.2;
      circleShapeDef.density = 1;
      circleShapeDef.restitution = 0.8;
      circleBody = world.CreateBody(circleBodyDef);
      circleBody.CreateShape(circleShapeDef);
      circleBody.SetMassFromShapes();
      circleSp = new Sprite();
      circleSp.graphics.beginFill(0xDDDDDD);
      circleSp.graphics.lineStyle(0,0xAAAAAA);
      circleSp.graphics.drawCircle(0,0,20);
      circleSp.graphics.endFill();
      circleBody.m_userData = circleSp;
      ballStage.addChild(circleSp);
      circleSp.addEventListener(MouseEvent.MOUSE_DOWN, h_mouseDown);
      circleSp.addEventListener(MouseEvent.MOUSE_UP, h_mouseUp);
      circles.push(circleBody);

    }


    private function h_enterFrame(event:Event):void {
      if (world == null) {
        return;
      }
      // drag
      lineStage.graphics.clear();
      if (bDrag) {
        dTarget.SetLinearVelocity(new b2Vec2(  (mouseX / DRAW_SCALE - dTarget.GetWorldCenter().x) * 5,
                                                (mouseY / DRAW_SCALE - dTarget.GetWorldCenter().y) * 5 ));
      }
      
      // step
      world.Step(1 / fps, 10);
      
      // draw
      var c:b2Body;
      for (var i:uint = 0; i < circles.length; i ++) {
        c = circles[i];
        c.GetUserData().x = c.GetWorldCenter().x * DRAW_SCALE;
        c.GetUserData().y = c.GetWorldCenter().y * DRAW_SCALE;
      }
      lineStage.graphics.clear();
      if (bDrag) {
        var tx = dTarget.GetWorldCenter().x;
        var ty = dTarget.GetWorldCenter().y;
        lineStage.graphics.lineStyle(0,0xAAAAFF);
        lineStage.graphics.moveTo(dTarget.GetUserData().x, dTarget.GetUserData().y);
        lineStage.graphics.lineTo(mouseX, mouseY);
      }
      
    }
    
  }
}