Box2Dの導入ログ

ということで、別の物理エンジンとしてBox2Dをさわってみることにした。

導入

Box2DFlashAS3 download | SourceForge.netのDownloadから、下の〜.zipを選んで解凍。
いつものごとく「flex_sdk_2\frameworks\source」に「Box2D」のフォルダをコピー。


付属のサンプルは「General」フォルダとかも必要そうなので、それとは別にBox2DFlashAS3 の単純なサンプルと使い方 - てっく煮ブログ 跡地を参考にサンプル作成。


ひとまず、床と球は作れたが、球が跳ねないのと、まだ意味(必要性)がわかってない変数(m_physScale)があるので、もう少し調査することにする。

コード

参考にさせてもらったサンプルを半分くらい流用。Box2D内のサンプルの円の描画が独特だったのは、描画の高速化と関連するんだろうか。


このサンプルだと球が跳ねないが、アクションゲームに使う場合はむしろ跳ねない方がうれしい。

package {
	import Box2D.Dynamics.*;
	import Box2D.Collision.*;
	import Box2D.Collision.Shapes.*;
	import Box2D.Common.Math.*;
	import flash.events.Event
	import flash.display.*;
	import flash.text.TextField;

	[SWF(backgroundColor="#ffffff", width="350", height="200")]
	public class Main extends Sprite {
		private var m_world:b2World;
		private var m_physScale:Number = 10;

		public function Main() {
			stage.scaleMode = "noScale";
			stage.align = "TL";

			{//Init Box2D
				{//Common
					//AABB
					var worldAABB:b2AABB = new b2AABB();
					worldAABB.minVertex.Set(-100.0, -100.0);
					worldAABB.maxVertex.Set(100.0, 100.0);
					//Gravity
					var gravity:b2Vec2 = new b2Vec2(0.0, 10.0);
					//World
					m_world = new b2World(worldAABB, gravity, true);
				}

				{//Floor
					//Shape
					var wallSd:b2BoxDef = new b2BoxDef();
					{
						wallSd.extents.Set(300 / m_physScale / 2, 10 / m_physScale);
//						wallSd.localRotation = Math.random() * Math.PI / 8;
						wallSd.restitution = 0.5;
					}
					//Body
					var wallBd:b2BodyDef = new b2BodyDef();
					{
						wallBd.position.Set(300 / m_physScale / 2, 250 / m_physScale);
						wallBd.AddShape(wallSd);
					}
					//Create
					m_world.CreateBody(wallBd);
				}

				{//Sphere
					//Shape
					var ballSd:b2CircleDef = new b2CircleDef();
					{
						ballSd.radius = 30 / m_physScale;
//						ballSd.localRotation = Math.random() * Math.PI / 8;
						ballSd.density = 1;
						ballSd.friction = 0.2;
						ballSd.restitution = 0.8;
					}
					//Body
					var ballBd:b2BodyDef = new b2BodyDef();
					{
						ballBd.position.Set(300 / m_physScale / 2, 20 / m_physScale);
						ballBd.AddShape(ballSd);
					}
					//Create
					m_world.CreateBody(ballBd);
				}
			}

			addEventListener("enterFrame", function(event:Event):void {
				Update();
			});
		}

		public function Update():void {
			if(!m_world) {
				return;
			}

			m_world.Step(1 / 30, 10);

			// Render
			graphics.clear();
			for (var bb:b2Body = m_world.m_bodyList; bb; bb = bb.m_next) {
				for (var s:b2Shape = bb.GetShapeList(); s != null; s = s.GetNext()) {
					DrawShape(s);
				}
			}
		}

		public function DrawShape(shape:b2Shape):void {
			//box
			if(shape.m_type == b2Shape.e_polyShape) {
				var drawBox:Function = function():void{
					var poly:b2PolyShape = shape as b2PolyShape;
					var tV:b2Vec2 = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[i]));

					graphics.beginFill(0x999999, 1);
					graphics.lineStyle(1,0xffffff,1);
					graphics.moveTo(tV.x * m_physScale, tV.y * m_physScale);

					for (var i:int = 0; i < poly.m_vertexCount; ++i) {
						var v:b2Vec2 = b2Math.AddVV(poly.m_position, b2Math.b2MulMV(poly.m_R, poly.m_vertices[i]));
						graphics.lineTo(v.x * m_physScale, v.y * m_physScale);
					}
					graphics.lineTo(tV.x * m_physScale, tV.y * m_physScale);

					graphics.endFill();
				};

				drawBox();
			}

			//circle
			if(shape.m_type == b2Shape.e_circleShape) {
				var drawCircle:Function = function():void{
					var circle:b2CircleShape = shape as b2CircleShape;
					var pos:b2Vec2 = circle.m_position;
					var r:Number = circle.m_radius;

					graphics.beginFill(0x999999, 1);
					graphics.lineStyle(1,0xaaaaaa,1);

					graphics.drawCircle(pos.x * m_physScale, pos.y * m_physScale, r * m_physScale);

					graphics.endFill();
				};

				drawCircle();
			}

		}
	}
}