/*===================================================*//** * Box23DAS3 and Papervision3D Demo * Please drag stage balls * * ボールをジョイントでつないでみました * 注:Line3Dがリークしていて時間経過で負荷が高まっていきます>_< * * @author Yasu * @see http://clockmaker.jp/blog/ * @since 2009.04.05 *//*===================================================*/ package { import Box2D.Collision.Shapes.*; import Box2D.Collision.b2AABB; import Box2D.Common.Math.b2Vec2; import Box2D.Dynamics.Joints.*; import Box2D.Dynamics.*; import flash.net.*; import flash.ui.*; import flash.display.*; import flash.events.*; import flash.geom.*; import org.papervision3d.events.*; import org.papervision3d.lights.*; import org.papervision3d.materials.shadematerials.*; import org.papervision3d.objects.*; import org.papervision3d.view.*; import org.papervision3d.objects.primitives.*; import org.papervision3d.core.geom.renderables.*; import org.papervision3d.core.geom.*; import org.papervision3d.materials.special.*; import net.hires.debug.Stats; [SWF(width="464", height="465", frameRate="30")] public class Main extends BasicView { // const vars static public const OBJ_SIZE:int = 40; static public const OBJ_NUM:uint = 10; static public const OBJ_COLOR:uint = 0x3399FF; // vars for Box2D private var worldWidth:Number; private var worldHeight:Number; private var m_iterations:int; private var m_wallWidth:Number; private var m_wallHeight:Number; private var m_timeStep:Number; private var m_physScale:Number; private var m_world:b2World; private var m_mouseJoint:b2MouseJoint; private var m_draggedBody:b2Body; private var mouseXWorldPhys:Number; private var mouseYWorldPhys:Number; private var isMouseDown:Boolean; private var arrayIndex:int; // array of objs private var pv3dObjsArr:Vector.<DisplayObject3D> = new Vector.<DisplayObject3D>(OBJ_NUM, true); private var box3dSpapesArr:Vector.<b2Body> = new Vector.<b2Body>(OBJ_NUM, true); private var joints:Vector.<b2DistanceJoint> = new Vector.<b2DistanceJoint>(OBJ_NUM, true);; private var line3D:Line3D; private var lines3D:Lines3D; private var lm:LineMaterial; /** * Constructor */ public function Main() { stage.quality = StageQuality.LOW; // init PV3D super(465, 465, false, true); // for poligon cross problem, but it's heavy... //renderer = new QuadrantRenderEngine(QuadrantRenderEngine.QUAD_SPLIT_FILTER); // init PV3D World createPaervision3dWorld(); // init Box2D World createBox2dWorld() // 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); // Backgound createBackGround(); cerateFullScreenBtn(); // debug addChild(new Stats) } /** * Create Papervision3D World */ private function createPaervision3dWorld():void { camera.zoom = 1000 / camera.focus + 1; camera.x = 0; camera.z = -1000; // create light var light:PointLight3D = new PointLight3D(); light.z = -100; for(var i:int=0; i < OBJ_NUM; i++) { var mat:FlatShadeMaterial if(i == 0) mat = new FlatShadeMaterial(light, 0x990000); else mat = new FlatShadeMaterial(light, OBJ_COLOR); mat.interactive = true; var obj3d:DisplayObject3D = scene.addChild(new Sphere(mat, OBJ_SIZE/2, 6, 5)); obj3d.extra = { radius:OBJ_SIZE, arrayPos:i }; obj3d.x = - Math.random() * 200 + 100; obj3d.y = Math.random() * -200; obj3d.addEventListener(InteractiveScene3DEvent.OBJECT_PRESS, obj3dMousePressHandler); obj3d.addEventListener(InteractiveScene3DEvent.OBJECT_OVER, obj3dMouseOverHandler); obj3d.addEventListener(InteractiveScene3DEvent.OBJECT_OUT, obj3dMouseOutHandler); pv3dObjsArr[i] = obj3d; } // lines lines3D = new Lines3D(); scene.addChild(lines3D); lm = new LineMaterial(0xFFFFFF); } /** * Create Box2D World */ private function createBox2dWorld():void { // init Box2D worldWidth = stage.stageWidth; worldHeight = stage.stageHeight; m_iterations = 5; 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, 10); 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; // left wall wallShapeDef.SetAsBox(10 / m_physScale, m_wallHeight / 2 / 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, 0); wall = m_world.CreateBody(wallBodyDef); wall.CreateShape(wallShapeDef); // bottom wall wallBodyDef.position.Set(m_wallWidth / 2 / m_physScale, m_wallHeight / m_physScale); wall = m_world.CreateBody(wallBodyDef); wall.CreateShape(wallShapeDef); wall.SetMassFromShapes(); for(var i:int=0; i < OBJ_NUM; i++) { var obj3d:DisplayObject3D = pv3dObjsArr[i]; var boxShape:b2CircleDef = new b2CircleDef(); boxShape.radius = OBJ_SIZE / m_physScale / 2; boxShape.density = 3; boxShape.friction = 10; boxShape.restitution = 0.75; 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(boxShape); body.SetUserData(obj3d); body.SetMassFromShapes(); box3dSpapesArr[i] = body; } // create joints for (i = 1; i < box3dSpapesArr.length; i++) { // joint to balls from drag obj var jointDef:b2DistanceJointDef = new b2DistanceJointDef(); jointDef.Initialize( box3dSpapesArr[0], box3dSpapesArr[i], box3dSpapesArr[0].GetPosition(), box3dSpapesArr[i].GetPosition()); var joint:b2DistanceJoint = m_world.CreateJoint(jointDef) as b2DistanceJoint; joint.m_length = 1; joint.m_frequencyHz = 1.5; joint.m_dampingRatio = 0; } } /** * get mouse position, and convert box2d scale */ private function updateMouseWorld():void { mouseXWorldPhys = mouseX / m_physScale; mouseYWorldPhys = mouseY / m_physScale; } /** * Enter Frame * @param event */ 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 DisplayObject3D) { bb.GetUserData().x = bb.GetPosition().x * m_physScale - worldWidth / 2; bb.GetUserData().y = -bb.GetPosition().y * m_physScale + worldHeight / 2; bb.GetUserData().rotationZ = -bb.GetAngle() * (180 / Math.PI); } } // lines lines3D.removeAllLines(); for (var i:int = 1; i < pv3dObjsArr.length; i++) { var os:DisplayObject3D = pv3dObjsArr[0]; var oe:DisplayObject3D = pv3dObjsArr[i]; var startV:Vertex3D = new Vertex3D(os.x, os.y, os.z); var endV:Vertex3D = new Vertex3D(oe.x, oe.y, oe.z); var line:Line3D = new Line3D(lines3D, lm, 1, startV, endV); lines3D.addLine(line); } singleRender(); } /** * 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 = 3000 * 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); } } /** * Mouse Down * @param event */ private function mouseDownHandler(event:MouseEvent):void { isMouseDown = true; } /** * Mouse Up * @param event */ 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:InteractiveScene3DEvent):void { arrayIndex = (event.target as DisplayObject3D).extra.arrayPos; } private function obj3dMouseOverHandler(e:InteractiveScene3DEvent):void { Mouse.cursor = MouseCursor.HAND; } private function obj3dMouseOutHandler(e:InteractiveScene3DEvent):void { if(!isMouseDown) Mouse.cursor = MouseCursor.ARROW; } private function createBackGround():void { var bgMatrix:Matrix = new Matrix(); bgMatrix.rotate(90 * Math.PI / 180); graphics.beginGradientFill("linear", [0xFFFFFF, 0x001122], [100, 100], [0, 255], bgMatrix); graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight); } private function cerateFullScreenBtn():void { var btn:Sprite = new Sprite(); var loader:Loader = new Loader(); loader.load(new URLRequest("http://wonderfl.kayac.com/img/code/out_arrow_o.gif")); btn.addChild(loader); btn.x = 435; btn.y = 5; btn.buttonMode = true; btn.addEventListener(MouseEvent.CLICK, function():void { if (stage.displayState == StageDisplayState.FULL_SCREEN) stage.displayState = StageDisplayState.NORMAL; else stage.displayState = StageDisplayState.FULL_SCREEN; }); addChild(btn); } } } [Box2D][PV3D] 3D Ball Joint