Math and (Quasi) Physics in Action Script 3

Box 2D + PaperVision3d - dropping tetrominos

An experiment to combine PaperVision3D with Box 2D

Main.as

´╗┐package {
  //box2d
  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;
  //pv3d
  import org.papervision3d.cameras.*;
  import org.papervision3d.materials.shadematerials.*;
  import org.papervision3d.materials.special.*;
  import org.papervision3d.materials.*;
  import org.papervision3d.materials.utils.*;
  import org.papervision3d.objects.*;
  import org.papervision3d.objects.primitives.*;
  import org.papervision3d.render.*;
  import org.papervision3d.scenes.*;
  import org.papervision3d.view.*;
  import org.papervision3d.lights.*;
  //
  import flash.display.*;
  import flash.events.*;
  import flash.geom.*;

  public class Main extends Sprite {
    private var cnt:uint = 0;
    private var fps:uint;

    private var world:b2World;

    private var scene:Scene3D;
    private var camera:Camera3D;
    private var viewport:Viewport3D;
    private var renderer:BasicRenderEngine;
    private var light:PointLight3D;
    private var b2dObj:Array = [];
    private var p3dObj:Array = [];

    private var blockDef:Array = [

    [[1,0],[2,0],[3,0],[4,0],0xff0000,0x880000],
    [[0,0],[1,0],[1,1],[0,1],0xffff00,0x888800],
    [[0,0],[0,1],[0,2],[1,1],0x00ffff,0x008888],
    [[0,0],[1,0],[1,1],[2,1],0x00ff00,0x008800],
    [[0,1],[1,1],[1,0],[2,0],0xff00ff,0x880088],
    [[0,0],[1,0],[2,0],[2,1],0x0000ff,0x000088],
    [[0,0],[1,0],[2,0],[0,1],0xff6600,0x883300]
    ];
    
    private var drawScale:uint = 20;
    
    public function Main():void {
      fps = stage.frameRate;
      addEventListener(Event.ENTER_FRAME, h_enterFrame);
      b2d_init();
      pv3d_init();
    }

    private function b2d_init():void {
      // create the world
      var worldAABB:b2AABB = new b2AABB();
      worldAABB.lowerBound.Set(-50, -50);
      worldAABB.upperBound.Set(50, 50);
      var gravity:b2Vec2 = new b2Vec2(0,10);
      world = new b2World(worldAABB,gravity,true);

      // create a floor box
      var floorBodyDef:b2BodyDef = new b2BodyDef();
      floorBodyDef.position.Set(6, 25);
      var floorShapeDef:b2PolygonDef = new b2PolygonDef();
      floorShapeDef.SetAsBox(200, 0.05);
      var floor:b2Body = world.CreateBody(floorBodyDef);
      floor.CreateShape(floorShapeDef);
      
      /*
      var debugSp:Sprite = new Sprite();
      addChild(debugSp);
      debugSp.alpha = 0.5;
      
      var debugDraw:b2DebugDraw = new b2DebugDraw();
      debugDraw.m_sprite = debugSp;
      debugDraw.m_drawScale = drawScale;
      debugDraw.m_fillAlpha = 0.3;
      debugDraw.m_lineThickness = 1;
      debugDraw.m_drawFlags = b2DebugDraw.e_shapeBit;
      world.SetDebugDraw(debugDraw);
      */
    }

    public function pv3d_init():void {
      //bg
      graphics.beginFill(0x000000);
      graphics.drawRect(0,0,450,450);
      scene = new Scene3D();
      //camera
      camera = new Camera3D();
      camera.focus = 100;
      camera.zoom = 10;
      //vieport
      viewport = new Viewport3D(450,450);
      addChild(viewport);

      //renderer
      renderer = new BasicRenderEngine();

      //light
      light = new PointLight3D();
      light.x = 10;
      light.y = 10;
      light.z = -10;
      scene.addChild(light);
    }

    private function h_enterFrame(event:Event):void {
      if (world == null) {
        return;
      }

      if (cnt++  %60 == 0 && b2dObj.length < 50) {
        createBlock();
      }
      world.Step(2 / fps, 10);
      
      var v2d:b2Vec2;
      for (var i:uint = 0; i < b2dObj.length; i ++) {
        v2d = b2dObj[i].GetWorldCenter();
        p3dObj[i].x = v2d.x * drawScale;
        p3dObj[i].y = -v2d.y * drawScale;
        p3dObj[i].rotationZ = -b2dObj[i].GetAngle() * 180 / Math.PI;
      }
      
      camera.x = Math.sin(cnt / 100) * 1000;
      camera.z = Math.cos(cnt / 100) * 1000;
      camera.y = 300;
      camera.lookAt(p3dObj[p3dObj.length - 1]);
      renderer.renderScene(scene, camera, viewport);
    }

    private function createBlock():void {
      
      var i:uint,j:uint;      
      j = Math.random() * blockDef.length;
      
      //box2d
      var blockBodyDef:b2BodyDef;
      var blockShapeDef:b2PolygonDef;
      var blockBody:b2Body;
      blockBodyDef = new b2BodyDef();
      
      blockBodyDef.position.Set(6, 6);
      blockBody = world.CreateBody(blockBodyDef);

      for (i = 0; i < blockDef[j].length - 2; i ++) {
        blockShapeDef = new b2PolygonDef();
        blockShapeDef.vertexCount = 4;

        blockShapeDef.vertices[0].Set(blockDef[j][i][0], blockDef[j][i][1]);
        blockShapeDef.vertices[1].Set(blockDef[j][i][0] + 1, blockDef[j][i][1]);
        blockShapeDef.vertices[2].Set(blockDef[j][i][0] + 1, blockDef[j][i][1] + 1);
        blockShapeDef.vertices[3].Set(blockDef[j][i][0], blockDef[j][i][1] + 1);
        blockShapeDef.density = 1;
        blockShapeDef.restitution = 0.4;
        blockBody.CreateShape(blockShapeDef);
      }

      blockBody.SetMassFromShapes();
      var center:b2Vec2 = blockBody.GetLocalCenter();

      b2dObj.push(blockBody);
      
      //pv3d
      var material:PhongMaterial = new PhongMaterial(light, blockDef[j][4], blockDef[j][5],4);
      var mList:MaterialsList = new MaterialsList();
      mList.addMaterial(material ,"all");
      var obj:DisplayObject3D = new DisplayObject3D;
      var cube:Cube;
      for (i = 0; i < blockDef[j].length - 2; i ++) {
        cube = new Cube(mList,drawScale,drawScale,drawScale);
        cube.x = (blockDef[j][i][0] - center.x +0.5) * drawScale  ;
        cube.y = -(blockDef[j][i][1] - center.y + 0.5) * drawScale;
        obj.addChild(cube);
      }
      
      obj.x  = 1;
      obj.y = 1;
      //objs.push(obj);
      scene.addChild(obj);
      p3dObj.push(obj);
    }
  }
}