Box2DFlashAS3を使って作る物理演算ゲーム サンプルコード ll_koba_ll forked:0favorite:2lines:239license : MIT License modified : 2009-11-18 23:13:49 Embed Tweet package { import flash.display.*; import flash.events.*; import flash.ui.Keyboard; import Box2D.Dynamics.*; import Box2D.Collision.*; import Box2D.Collision.Shapes.*; import Box2D.Dynamics.Joints.*; import Box2D.Dynamics.Contacts.*; import Box2D.Common.*; import Box2D.Common.Math.*; import com.flashdynamix.utils.SWFProfiler; [SWF(frameRate=30, width=500, height=500, backgroundColor="#000000")] public class Box2DSample01 extends Sprite { private var _world:b2World; private const DRAW_SCALE:Number = 100; private var _iterations:int = 10; private var _timeStep:Number = 1.0/30.0; private var _debug:Boolean = false; private var _gravity:b2Vec2; private var _doSleep:Boolean = true; private var _shipBody:b2Body; private var _goalBody:b2Body; private var _startBody:b2Body; private var _shipView:ShipView; private var _shipModel:ShipModel; public function Box2DSample01() { addEventListener(Event.ENTER_FRAME, function():void { if (stage != null) { removeEventListener(Event.ENTER_FRAME, arguments.callee); init(); } }); _shipModel = new ShipModel(); SWFProfiler.init(this); } private function init(e:Event = null):void { addEventListener(Event.ENTER_FRAME, update) stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler); stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler); var worldAABB:b2AABB = new b2AABB(); // 物理エンジンの範囲を決定 worldAABB.lowerBound.Set(-100, -100); worldAABB.upperBound.Set(100, 100); // 重力の設定 _gravity = new b2Vec2(0, 1); // ワールドの生成 _world = new b2World(worldAABB, _gravity, _doSleep); // デバッグ表示 if (_debug) { var dbgDraw:b2DebugDraw = new b2DebugDraw(); var dbgSprite:Sprite = new Sprite(); addChild(dbgSprite); dbgDraw.m_sprite = dbgSprite; dbgDraw.m_drawScale = DRAW_SCALE; dbgDraw.m_fillAlpha = 0.0; dbgDraw.m_alpha = 1.0; dbgDraw.m_lineThickness = 1.0; dbgDraw.m_drawFlags = 0xFFFFFFFF; _world.SetDebugDraw(dbgDraw); } // 各オブジェクトの生成 var stw:Number = stage.stageWidth; var sth:Number = stage.stageHeight; createBox("floor", stw/2, sth, stw, 10); createBox("ceiling", stw/2, 0, stw, 10); createBox("leftWall", 0, sth/2, 10, sth); createBox("rightWall", stw, sth/2, 10, sth); createBox("start", 40, sth - 10, 60, 10); createBox("goal", stw - 40, sth - 10, 60, 10); createBox("centerWall", stw/2, sth/2 + 90/2, 20, sth - 90); initShip(); // 衝突判定用のリスナー設定 var cl:ContactListener = new ContactListener(this); _world.SetContactListener(cl); } public function gameClear():void { trace("gameClear"); } public function gameOver():void { trace("gameOver"); } private function initShip():void { // body生成 var bodyDef:b2BodyDef; bodyDef = new b2BodyDef(); bodyDef.position.x = 40/DRAW_SCALE; bodyDef.position.y = (stage.stageHeight - 40)/DRAW_SCALE; bodyDef.userData = {}; bodyDef.userData.id = "ship"; // 表示オブジェクト設定 _shipView = new ShipView(); bodyDef.userData.displayObject = _shipView; addChild(bodyDef.userData.displayObject); // shape生成 var boxDef:b2PolygonDef; boxDef = new b2PolygonDef(); boxDef.SetAsBox(40/2/DRAW_SCALE, 40/2/DRAW_SCALE); boxDef.density = 0.1; // 密度 boxDef.friction = 0.5; // 摩擦係数 boxDef.restitution = 0.2; // 反発係数 // ワールドに追加 var body:b2Body; body = _world.CreateBody(bodyDef); body.CreateShape(boxDef); body.SetMassFromShapes(); _shipBody = body; } private function createBox(id:String, x:Number, y:Number, w:Number, h:Number):void { // body生成 var bodyDef:b2BodyDef = new b2BodyDef(); bodyDef.position.x = x/DRAW_SCALE; bodyDef.position.y = y/DRAW_SCALE; bodyDef.userData = {}; bodyDef.userData.id = id; // 表示オブジェクト作成 var display:Sprite = new Sprite(); var g:Graphics = display.graphics; g.lineStyle(1, 0xFFFFFF); g.drawRect(-w/2,-h/2,w,h); addChild(display); bodyDef.userData.displayObject = display; // Shape生成 var boxDef:b2PolygonDef = new b2PolygonDef(); boxDef.SetAsBox(w/2/DRAW_SCALE, h/2/DRAW_SCALE); boxDef.density = 0; // 固定されたオブジェクトに // ワールドに追加 var body:b2Body = _world.CreateBody(bodyDef); body.CreateShape(boxDef); } private function update(event:Event):void { if (_world == null) return; _world.Step(_timeStep, 10); for (var bb:b2Body = _world.m_bodyList; bb; bb = bb.m_next) { updateBodys(bb); // m_userDataに表示オブジェクトが入っている場合は、表示オブジェクトに計算結果を反映 if (bb.m_userData) { if (bb.m_userData.displayObject is Sprite) { bb.m_userData.displayObject.x = bb.GetPosition().x * DRAW_SCALE; bb.m_userData.displayObject.y = bb.GetPosition().y * DRAW_SCALE; bb.m_userData.displayObject.rotation = bb.GetAngle() * (180/Math.PI); if(bb.m_userData.displayObject.y > stage.stageHeight ) { removeChild(bb.m_userData.displayObject); _world.DestroyBody(bb); } } } } // 宇宙船を更新 var a:Number = ((_shipBody.GetAngle() * 180/Math.PI) - 90) * Math.PI/180; var vx:Number = Math.cos(a) * _shipModel.power; var vy:Number = Math.sin(a) * _shipModel.power; var v:b2Vec2 = _shipBody.GetLinearVelocity(); if (_shipModel.power > 0) { _shipBody.SetLinearVelocity(new b2Vec2(v.x + vx, v.y + vy)); } _shipBody.SetAngularVelocity(_shipModel.vr * Math.PI/180); } private function updateBodys(body:b2Body):void { } private function keyDownHandler(e:KeyboardEvent):void { // shipBodyがsleepしてる可能性があるので _shipBody.WakeUp(); switch(e.keyCode) { case Keyboard.UP: _shipView.showFire(); _shipModel.power = 0.1; break; case Keyboard.LEFT: _shipModel.vr = -50; break; case Keyboard.RIGHT: _shipModel.vr = 50; break; } } private function keyUpHandler(e:KeyboardEvent):void { switch(e.keyCode) { case Keyboard.UP: _shipView.hideFire(); _shipModel.power = 0; break; case Keyboard.LEFT: case Keyboard.RIGHT: _shipModel.vr = 0; break; } } } } import flash.display.*; class ShipModel { public var power:Number = 0; public var vr:Number = 0; } class ShipView extends Sprite { private var _fire:Sprite; public function ShipView() { var g:Graphics = graphics; g.lineStyle(1, 0xFFFFFF); g.drawRect(-20,-20, 40, 40); _fire = new Sprite(); g = _fire.graphics; g.lineStyle(1, 0xFF0000); g.moveTo(-10, 0); g.lineTo(0, 20); g.lineTo(10, 0); g.lineTo(-10, 0); _fire.y = 23; _fire.visible = false; addChild(_fire); } public function showFire():void { _fire.visible = true; } public function hideFire():void { _fire.visible = false; } } import Box2D.Collision.Shapes.*; import Box2D.Collision.b2ContactPoint; import Box2D.Dynamics.b2ContactListener; import Box2D.Dynamics.*; class ContactListener extends b2ContactListener { private var _gameStage:Box2DSample01; public function ContactListener(gameStage:Box2DSample01) { _gameStage = gameStage; } public override function Add(point:b2ContactPoint):void { var s1:b2Shape = point.shape1; var s2:b2Shape = point.shape2; var b1:b2Body = s1.m_body; var b2:b2Body = s2.m_body; if (b1.m_userData == null && b2.m_userData == null) return; // b1が宇宙船の場合 if (b1.m_userData != null && b1.m_userData.id == "ship") { if (b2.m_userData.id != "start" && b2.m_userData.id != "goal") { _gameStage.gameOver(); } else if (b2.m_userData.id == "goal") { _gameStage.gameClear(); } } // b2が宇宙船の場合 if (b2.m_userData != null && b2.m_userData.id == "ship") { if (b1.m_userData.id != "start" && b1.m_userData.id != "goal") { _gameStage.gameOver(); } else if (b1.m_userData.id == "goal") { _gameStage.gameClear(); } } } } Code Fullscreen Preview Fullscreen bradsedito OKASUKE web+db54 b2Body display visible b2BodyDef b2PolygonDef id b2Vec2 m_userData userData b2Shape b2DebugDraw Keyboard.UP CreateShape Keyboard.RIGHT Keyboard.LEFT GetLinearVelocity density GetPosition SetAsBox SetAngularVelocity