package { import Box2D.Collision.b2AABB; import Box2D.Collision.Shapes.b2CircleDef; import Box2D.Collision.Shapes.b2PolygonDef; import Box2D.Collision.Shapes.b2PolygonShape; import Box2D.Common.Math.b2Vec2; import Box2D.Dynamics.b2Body; import Box2D.Dynamics.b2BodyDef; import Box2D.Dynamics.b2DebugDraw; import Box2D.Dynamics.b2World; import Box2D.Dynamics.Joints.b2MouseJoint; import Box2D.Dynamics.Joints.b2MouseJointDef; import Box2D.Dynamics.Joints.b2RevoluteJoint; import Box2D.Dynamics.Joints.b2RevoluteJointDef; import flash.display.Bitmap; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; public class PaintedFloor extends Sprite { // 物理エンジン内の1mを表すためのピクセル数 private static const DRAW_SCALE:Number = 100; // 物理エンジンの管理クラス private var world:b2World; // 車体 private var body:b2Body; // 前輪 private var frontWheel:b2Body; // 後輪 private var rearWheel:b2Body; // マウスジョイントの定義 private var mouseJointDef:b2MouseJointDef; // マウスジョイント private var mouseJoint:b2MouseJoint; // Flashに画像を埋め込む [Embed(source='floor.png')] private static const FloorImage:Class; [Embed(source='body.png')] private static const BodyImage:Class; [Embed(source='wheel.png')] private static const WheelImage:Class; public function CarFinal() { //////////////////////////////////////// // 物理エンジンのセットアップ // 外枠を定義する var worldAABB:b2AABB = new b2AABB(); worldAABB.lowerBound.Set(-100, -100); worldAABB.upperBound.Set(100, 100); // 重力を下方向に10m/s^2とする var gravity:b2Vec2 = new b2Vec2(0, 10); // 外枠と重力を指定して、物理エンジン全体をセットアップする world = new b2World(worldAABB, gravity, true); //////////////////////////////////////// // 床の設置 // 床は画面の下のほうに設置します // 床の位置を左から2.5m、上から3mとする var floorBodyDef:b2BodyDef = new b2BodyDef(); floorBodyDef.position.Set(2.5, 3); // 床の形を、幅4m、厚さ20cmとする // 指定するのはその半分の値 var floorShapeDef:b2PolygonDef = new b2PolygonDef(); floorShapeDef.SetAsBox(2, 0.1); // 床を動かない物体として作る var floor:b2Body = world.CreateStaticBody(floorBodyDef); floor.CreateShape(floorShapeDef); // 床の画像を作る var floorImage:Bitmap = new FloorImage(); // 画像のサイズを合わせる floorImage.width = 4 * DRAW_SCALE; floorImage.height = 0.2 * DRAW_SCALE; // 床の中心が(0, 0)に来るように,左上にずらす floorImage.x = -floorImage.width / 2; floorImage.y = -floorImage.height / 2; // b2BodyのユーザデータとしてSpriteを作る floor.m_userData = new Sprite(); // Spriteの場所を物理エンジン内の場所と一致させる floor.GetUserData().x = floor.GetWorldCenter().x * DRAW_SCALE; floor.GetUserData().y = floor.GetWorldCenter().y * DRAW_SCALE; floor.GetUserData().addChild(floorImage); addChild(floor.GetUserData()); //////////////////////////////////////// // 車体(body)を作る // 幅が80cm、高さが20cmで、場所は床の中心から少し上のところ var bodyDef:b2BodyDef = new b2BodyDef(); bodyDef.position.Set(2.5, 2); var bodyShape:b2PolygonDef = new b2PolygonDef(); bodyShape.SetAsBox(0.4, 0.1); bodyShape.density = 1; body = world.CreateDynamicBody(bodyDef); body.CreateShape(bodyShape); body.SetMassFromShapes(); //////////////////////////////////////// // 前輪(frontWheel)を作る // bodyDefは再利用できる bodyDef.position.Set(2.8, 2); var wheelShape:b2CircleDef = new b2CircleDef(); wheelShape.radius = 0.15; wheelShape.density = 1; frontWheel = world.CreateDynamicBody(bodyDef); frontWheel.CreateShape(wheelShape); frontWheel.SetMassFromShapes(); //////////////////////////////////////// // 後輪(rearWheel)を作る bodyDef.position.Set(2.2, 2); // wheelShapeも再利用できる rearWheel = world.CreateDynamicBody(bodyDef); rearWheel.CreateShape(wheelShape); rearWheel.SetMassFromShapes(); //////////////////////////////////////// // 車体と前輪をつなぐ // ジョイントを定義するjointDef変数 var jointDef:b2RevoluteJointDef = new b2RevoluteJointDef(); // つながれる2つの物体と、つなぐ位置(前輪の中央)を使って、定義を初期化する jointDef.Initialize(body, frontWheel, frontWheel.GetWorldCenter()); // 回転速度の設定(6で1秒に1回転ぐらい) jointDef.motorSpeed = 3; // トルクの設定(大きいほど坂道に強くなる) jointDef.maxMotorTorque = 1; // 車輪を回すようにする jointDef.enableMotor = true; // 回転ジョイントを作る var frontJoint:b2RevoluteJoint = b2RevoluteJoint(world.CreateJoint(jointDef)); //////////////////////////////////////// // 車体と後輪をつなぐ // つながれる2つの物体と、つなぐ位置(後輪の中央)を使って、定義を初期化する jointDef.Initialize(body, rearWheel, rearWheel.GetWorldCenter()); // 回転ジョイントを作る var rearJoint:b2RevoluteJoint = b2RevoluteJoint(world.CreateJoint(jointDef)); //////////////////////////////////////// // マウスジョイントの定義を作る mouseJointDef = new b2MouseJointDef(); mouseJointDef.body1 = world.GetGroundBody(); mouseJointDef.body2 = body; mouseJointDef.target = body.GetWorldCenter(); mouseJointDef.maxForce = 5; mouseJointDef.timeStep = 1 / 24; //////////////////////////////////////// // 描画設定 var debugDraw:b2DebugDraw = new b2DebugDraw(); debugDraw.m_sprite = this; debugDraw.m_drawScale = DRAW_SCALE; // 1mを100ピクセルにする debugDraw.m_fillAlpha = 0.3; // 不透明度 debugDraw.m_lineThickness = 1; // 線の太さ debugDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit; world.SetDebugDraw(debugDraw); // イベントハンドラを登録する addEventListener(Event.ENTER_FRAME, enterFrameHandler); stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler); stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler); stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler); } private function mouseMoveHandler(event:MouseEvent):void { if (mouseJoint) { // マウスが押された場所を物理エンジン内の座標系に変換する var x:Number = event.stageX / DRAW_SCALE; var y:Number = event.stageY / DRAW_SCALE; // マウスジョイントのカーソル位置を更新 mouseJoint.SetTarget(new b2Vec2(x, y)); } } private function mouseDownHandler(event:MouseEvent):void { mouseJoint = b2MouseJoint(world.CreateJoint(mouseJointDef)); } private function mouseUpHandler(event:MouseEvent):void { world.DestroyJoint(mouseJoint); mouseJoint = null; } private function enterFrameHandler(event:Event):void { // Flashはデフォルトで秒間24フレームなので、 // 物理シミュレーションを1/24秒進める world.Step(1 / 24, 10); } } }