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 CarFinal 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(); // 車体の画像を読み込んで表示する var bodyImage:Bitmap = new BodyImage() bodyImage.width = 0.8 * DRAW_SCALE; bodyImage.height = 0.2 * DRAW_SCALE; bodyImage.x = -bodyImage.width / 2; bodyImage.y = -bodyImage.height / 2; body.m_userData = new Sprite(); body.GetUserData().x = body.GetWorldCenter().x * DRAW_SCALE; body.GetUserData().y = body.GetWorldCenter().y * DRAW_SCALE; body.GetUserData().addChild(bodyImage); addChild(body.GetUserData()); //////////////////////////////////////// // 前輪(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(); // 前輪の画像を読み込んで表示する var frontWheelImage:Bitmap = new WheelImage(); frontWheelImage.width = 0.3 * DRAW_SCALE; frontWheelImage.height = 0.3 * DRAW_SCALE; frontWheelImage.x = -frontWheelImage.width / 2; frontWheelImage.y = -frontWheelImage.height / 2; frontWheel.m_userData = new Sprite(); frontWheel.GetUserData().x = frontWheel.GetWorldCenter().x * DRAW_SCALE; frontWheel.GetUserData().y = frontWheel.GetWorldCenter().y * DRAW_SCALE; frontWheel.GetUserData().addChild(frontWheelImage); addChild(frontWheel.GetUserData()); //////////////////////////////////////// // 後輪(rearWheel)を作る bodyDef.position.Set(2.2, 2); // wheelShapeも再利用できる rearWheel = world.CreateDynamicBody(bodyDef); rearWheel.CreateShape(wheelShape); rearWheel.SetMassFromShapes(); // 後輪の画像を読み込んで表示する var rearWheelImage:Bitmap = new WheelImage(); rearWheelImage.width = 0.3 * DRAW_SCALE; rearWheelImage.height = 0.3 * DRAW_SCALE; rearWheelImage.x = -rearWheelImage.width / 2; rearWheelImage.y = -rearWheelImage.height / 2; rearWheel.m_userData = new Sprite(); rearWheel.GetUserData().x = rearWheel.GetWorldCenter().x * DRAW_SCALE; rearWheel.GetUserData().y = rearWheel.GetWorldCenter().y * DRAW_SCALE; rearWheel.GetUserData().addChild(rearWheelImage); addChild(rearWheel.GetUserData()); //////////////////////////////////////// // 車体と前輪をつなぐ // ジョイントを定義する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 { // ワールド内の全てのb2Bodyに対する処理 for (var b:b2Body = world.GetBodyList(); b; b = b.GetNext()) { if (b.GetUserData() is Sprite) { // 物理エンジン内での位置と回転角度を反映させる b.GetUserData().x = b.GetWorldCenter().x * DRAW_SCALE; b.GetUserData().y = b.GetWorldCenter().y * DRAW_SCALE; b.GetUserData().rotation = b.GetAngle() * 180 / Math.PI; } } // Flashはデフォルトで秒間24フレームなので、 // 物理シミュレーションを1/24秒進める world.Step(1 / 24, 10); } } }