package { import flash.display.BitmapData; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import flash.events.TimerEvent; import flash.ui.Mouse; import flash.ui.MouseCursor; import flash.utils.Dictionary; import flash.utils.Timer; import Box2D.Collision.Shapes.b2CircleDef; import Box2D.Collision.Shapes.b2PolygonDef; import Box2D.Collision.b2AABB; import Box2D.Common.Math.b2Vec2; import Box2D.Dynamics.Joints.b2MouseJoint; import Box2D.Dynamics.Joints.b2MouseJointDef; import Box2D.Dynamics.b2Body; import Box2D.Dynamics.b2BodyDef; import Box2D.Dynamics.b2DebugDraw; import Box2D.Dynamics.b2World; import alternativa.engine3d.core.Object3D; import alternativa.engine3d.core.events.MouseEvent3D; import alternativa.engine3d.lights.OmniLight; import alternativa.engine3d.materials.VertexLightTextureMaterial; import alternativa.engine3d.primitives.GeoSphere; import alternativa.engine3d.resources.BitmapTextureResource; import caurina.transitions.Tweener; import org.libspark.alternativa3d.view.AlternativaTemplate; [SWF(frameRate = "60", width = "800", height = "600")] public class Main extends AlternativaTemplate { public static const OBJ_COLOR:uint = 0x666666; public static const OBJ_NUM:uint = 20; // const vars public static const OBJ_SIZE:int = 160; /** * Constructor */ public function Main() { super(800, 600, false, 0xFFFFFF, 1, 1); } private var arrayIndex:int; private var box3dSpapesArr:Vector. = new Vector.(); private var dictionary:Dictionary = new Dictionary(); private var isMouseDown:Boolean; private var light:OmniLight; private var m_draggedBody:b2Body; private var m_iterations:int; private var m_mouseJoint:b2MouseJoint; private var m_physScale:Number; private var m_timeStep:Number; private var m_wallHeight:Number; private var m_wallWidth:Number; private var m_world:b2World; private var material:VertexLightTextureMaterial; private var mouseXWorldPhys:Number; private var mouseYWorldPhys:Number; // array of objs private var pv3dObjsArr:Vector. = new Vector.(); // timer count private var timerCnt:int = 0; private var worldHeight:Number; // vars for Box2D private var worldWidth:Number; override protected function atInit():void { // init PV3D World createPaervision3dWorld(); // init Box2D World createBox2dWorld() // add Objects for (var i:int = 0; i < OBJ_NUM; i++) { addObjectAtPv3dWorld(); addObjectAtBox2dWorld(); } // init vars for drag arrayIndex = -1; isMouseDown = false; // addEvent addEventListener(Event.ENTER_FRAME, enterFrameHandler); stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler); stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler); var timer:Timer = new Timer(1000); timer.addEventListener(TimerEvent.TIMER, timerHandler); timer.start(); } /** * Create Papervision3D World */ private function createPaervision3dWorld():void { // camera.zoom = 1000 / camera.focus + 1; cameraController.setObjectPosXYZ(0, -3000, 0); cameraController.lookAtXYZ(0, 0, 0); camera.fov = Math.PI * 1 / 10; // create light light = new OmniLight(0xFFFFFF, 0, 9000); light.y = -1000; scene.addChild(light); var texture:BitmapTextureResource = new BitmapTextureResource(new BitmapData(2, 2, true, 0xFF000000 + OBJ_COLOR)); material = new VertexLightTextureMaterial(texture); } /** * Create Box2D World */ private function createBox2dWorld():void { // init Box2D worldWidth = stage.stageWidth; worldHeight = stage.stageHeight; m_iterations = 30; 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, 30); var doSleep:Boolean = true; m_world = new b2World(worldAABB, gravity, doSleep); // craete wall for Box2D var wallShapeDef:b2PolygonDef = new b2PolygonDef(); var wallBodyDef:b2BodyDef = new b2BodyDef(); var wall:b2Body; m_wallWidth = stage.stageWidth; m_wallHeight = stage.stageHeight * 2; // left wall wallShapeDef.SetAsBox(10 / m_physScale, m_wallHeight / m_physScale); wallBodyDef.position.Set(0, m_wallHeight / 2 / m_physScale); wall = m_world.CreateBody(wallBodyDef); wall.CreateShape(wallShapeDef); // right wall wallBodyDef.position.Set(m_wallWidth / m_physScale, m_wallHeight / 2 / m_physScale); wall = m_world.CreateBody(wallBodyDef); wall.CreateShape(wallShapeDef); // upper wall wallShapeDef.SetAsBox(m_wallWidth / 2 / m_physScale, 10 / m_physScale); wallBodyDef.position.Set(m_wallWidth / 2 / m_physScale, -m_wallHeight / 2 / m_physScale); wall = m_world.CreateBody(wallBodyDef); wall.CreateShape(wallShapeDef); // bottom wall wallBodyDef.position.Set(m_wallWidth / 2 / m_physScale, m_wallHeight / 2 / m_physScale); wall = m_world.CreateBody(wallBodyDef); wall.CreateShape(wallShapeDef); wall.SetMassFromShapes(); /* var dbgDraw:b2DebugDraw = new b2DebugDraw();//デバッグオブジェクトを生成 var dbgSprite:Sprite = new Sprite();//デバッグ用オブジェクトの表示用sprite addChild(dbgSprite);//表示用スプライトを表示 dbgDraw.m_sprite = dbgSprite;//これはお決まり。 dbgDraw.m_drawScale = m_physScale;//ここでm_physScaleと違う値を入れると思わぬ表示になってしまう。 m_world.SetDebugDraw(dbgDraw); dbgDraw.m_fillAlpha = 0.5;//デバッグ用オブジェクトの透明度。表示されるオブジェクト全体に設定される。 dbgDraw.m_lineThickness = 0;//デバッグ用オブジェクトのライン。 dbgDraw.m_drawFlags = 0xFFFFFFFF;//デバッグ用オブジェクトの色指定。 */ } /** * AddItem at Papervision3D World */ private function addObjectAtPv3dWorld():void { var size:Number = OBJ_SIZE * Math.random() * 3 / 4 + OBJ_SIZE / 4; var obj3d:Object3D = scene.addChild(new GeoSphere(size / 2, 4, false, material)); pv3dObjsArr.push(obj3d); dictionary[ obj3d ] = { radius: size, arrayPos: pv3dObjsArr.length - 1 }; obj3d.x = -50 * Math.random() + 100; obj3d.z = Math.random() * -200 - 200; obj3d.addEventListener(MouseEvent3D.MOUSE_DOWN, obj3dMousePressHandler); obj3d.addEventListener(MouseEvent3D.MOUSE_OVER, obj3dMouseOverHandler); obj3d.addEventListener(MouseEvent3D.MOUSE_OUT, obj3dMouseOutHandler); } /** * AddItem at Box2D World */ private function addObjectAtBox2dWorld():void { var obj3d:Object3D = pv3dObjsArr[ pv3dObjsArr.length - 1 ]; var circleShape:b2CircleDef = new b2CircleDef(); circleShape.radius = dictionary[ obj3d ].radius / m_physScale / 2; circleShape.density = 1; circleShape.friction = 0.9; circleShape.restitution = 0.7; var bodyDef:b2BodyDef = new b2BodyDef(); bodyDef.position.Set((obj3d.x + worldWidth / 2) / m_physScale, (obj3d.y + worldHeight / 2) / m_physScale); var body:b2Body = m_world.CreateBody(bodyDef); body.CreateShape(circleShape); body.SetUserData(obj3d); body.SetMassFromShapes(); box3dSpapesArr.push(body); } /** * get mouse position, and convert box2d scale */ private function updateMouseWorld():void { mouseXWorldPhys = mouseX / m_physScale; mouseYWorldPhys = mouseY / m_physScale; } /** * Enter Frame */ private function enterFrameHandler(event:Event):void { // update Box2D step updateMouseWorld(); mouseDrag(); 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.GetUserData() is Object3D) { var obj3d:Object3D = bb.GetUserData() as Object3D; obj3d.x = bb.GetPosition().x * m_physScale - worldWidth / 2; obj3d.z = -bb.GetPosition().y * m_physScale + worldHeight / 2; obj3d.rotationY = -bb.GetAngle(); } } } /** * Drag And Drop */ private function mouseDrag():void { if (isMouseDown && !m_mouseJoint) { m_draggedBody = null; if (arrayIndex > -1) m_draggedBody = box3dSpapesArr[ arrayIndex ]; if (m_draggedBody) { var md:b2MouseJointDef = new b2MouseJointDef(); md.body1 = m_world.GetGroundBody(); md.body2 = m_draggedBody; md.target.Set(mouseXWorldPhys, mouseYWorldPhys); md.maxForce = 100000 * m_draggedBody.GetMass(); md.timeStep = m_timeStep; m_mouseJoint = m_world.CreateJoint(md) as b2MouseJoint; m_draggedBody.WakeUp(); } } if (!isMouseDown) { if (m_mouseJoint) { m_world.DestroyJoint(m_mouseJoint); m_mouseJoint = null; } } if (m_mouseJoint) { var p2:b2Vec2 = new b2Vec2(mouseXWorldPhys, mouseYWorldPhys); m_mouseJoint.SetTarget(p2); } } private function mouseDownHandler(event:MouseEvent):void { isMouseDown = true; } private function mouseUpHandler(event:MouseEvent):void { Mouse.cursor = MouseCursor.ARROW; isMouseDown = false; arrayIndex = -1; } /** * get number of pv3d clicked obj * @param event */ private function obj3dMousePressHandler(event:MouseEvent3D):void { // don't delete when current dragging if (arrayIndex == timerCnt) return; arrayIndex = dictionary[(event.target as Object3D)].arrayPos; } private function obj3dMouseOverHandler(e:MouseEvent3D):void { Mouse.cursor = MouseCursor.HAND; } private function obj3dMouseOutHandler(e:MouseEvent3D):void { if (!isMouseDown) Mouse.cursor = MouseCursor.ARROW; } /** * Timer Event Handler * @param e */ private function timerHandler(e:TimerEvent):void { // don't delete when current dragging if (arrayIndex == timerCnt) return; return; Tweener.addTween(pv3dObjsArr[ timerCnt ], { scaleX: 0, scaleY: 0, scaleZ: 0, time: 0.6, transition: "easeInOutExpo", onComplete: function():void { // don't delete when current dragging if (arrayIndex == timerCnt) return; //delete scene.removeChild(pv3dObjsArr[ timerCnt ]); pv3dObjsArr[ timerCnt ] = null; m_world.DestroyBody(box3dSpapesArr[ timerCnt ]); box3dSpapesArr[ timerCnt ] = null; addObjectAtPv3dWorld(); addObjectAtBox2dWorld(); timerCnt++; } }) } } }