最近、Box2Dエンジンの使用方法を説明した記事が公開されました。
ただし、サイトのエンジンはバージョン2.1aであり、残念ながらこの記事で提供されている作業とは異なる作業を行っています。 残念ながら、このバージョンのエンジンに関するわずかな外国のドキュメントは、私に多くを理解させました。 親愛なる読者の皆さん、私の研究の一部を共有したいと思います。
まず、バージョン2.0からの変更点についてお話します。
- 図形の幾何学的特性は物理的性質から分離されていました。 現在、物理プロパティはb2FixtureDefタイプであり、幾何プロパティはb2BodyDefタイプです。 物理プロパティをジオメトリに適用するには、物理プロパティのパラメーターを使用して、ボディ(b2Body)の CreateFixture関数を呼び出す必要があります。
body.CreateFixture(fixtureDef);
- また、b2BodyDefでオブジェクトのタイプを指定する必要があります。 次の3つのタイプがあります。
- 静的
- ダイナミック
- キネマティック(オブジェクトを移動したいが、他のオブジェクトと一緒に移動することが不可能だった場合)
- 今、私たちの世界の大きさを示す必要はありません。
- ポリゴン数の制限が削除されました。
新しいバージョンを学ぶために、例を見てみましょう。
最初に、新しいプロジェクトを作成する必要があります(私はFlashDevelopを使用しています) 。
package { import flash.display.Sprite; import flash.events.Event; public class Main extends Sprite { public function Main():void { if (stage) init(); else addEventListener(Event.ADDED_TO_STAGE, init); } public function init(e:Event = null):void { removeEventListener(Event.ADDED_TO_STAGE, init); } } }
次に、エンジンの2.1aバージョンをダウンロードし、プロジェクトのコードを含むフォルダーにドロップします。
必要なクラスをインポートします。
import Box2D.Common.Math.b2Vec2; import Box2D.Dynamics.*; import Box2D.Collision.Shapes.b2PolygonShape; import Box2D.Collision.Shapes.b2CircleShape; import flash.display.Sprite; import flash.events.Event; import flash.events.KeyboardEvent; import flash.utils.getTimer;
必要な変数を作成します。
public var PIXELS_TO_METRE:Number = new Number(30); // . , Box2D . public var world:b2World; // . public var ball:b2Body; //. public var timer:Number = new Number(0); // .
ADDED_TO_STAGEハンドラーを削除した後、ワールドを作成します。
world = new b2World(new b2Vec2(0, 10), true);
タイプb2Vec2のオブジェクトをとる最初のパラメーターは、世界の重力です。 この場合、y軸に沿って10ポイント下に向けており、私に合っています。
2番目のパラメーターは、世界のオブジェクトのスリープの許可/禁止です。
次に、私たちの世界でオブジェクトを作成する必要があります。 長方形を作成する関数を作成することにしました。
public function addBox(x:Number, y:Number, width:Number, height:Number, dyn:int = 0):b2Body { var bodyDef:b2BodyDef = new b2BodyDef(); bodyDef.position.Set((x + width / 2) / PIXELS_TO_METRE, (y + height / 2) / PIXELS_TO_METRE); if (dyn == 1) bodyDef.type = b2Body.b2_dynamicBody; var content:Sprite = new Sprite(); content.graphics.beginFill(0x000000); content.graphics.drawRect(0 - width / 2, 0 - height / 2, width, height); bodyDef.userData = content; addChild(bodyDef.userData); var boxShape:b2PolygonShape = new b2PolygonShape(); boxShape.SetAsBox(width / 2 / PIXELS_TO_METRE, height / 2 / PIXELS_TO_METRE); var fixtureDef:b2FixtureDef = new b2FixtureDef(); fixtureDef.shape = boxShape; fixtureDef.density = dyn; var body:b2Body = world.CreateBody(bodyDef); body.CreateFixture(fixtureDef); return(body); }
bodyDefオブジェクトには、四角形のパラメーター(座標、回転、内容)が格納されます。 最初は、座標点は長方形の中心です。 これは私にとって不便なので、パラメータとして入力される左上の点を計算しました。
このプロジェクトには、動的な(生きている)長方形と静的な長方形の両方があります。 パラメータ(dyn)を確認し、必要に応じてタイプを設定します。
次に、グラフィックコンポーネントである長方形自体を中心から描画します。
タイプb2PolygonShapeのオブジェクトのSetAsBoxメソッドは、オブジェクトの物理的な部分に長方形を割り当てます。 パラメーターとして、メーターも使用し、中央からカウントを開始します。
FixtureDefオブジェクトは、四角形の物理パラメーター、ダイナミズム、密度、弾性、物理モデルです。 密度や弾性などのパラメーターは使用しませんでした。
次に、オブジェクトに関するデータを世界に送信します。
次に、プロジェクトの主役であるボールを作成する関数を作成しました。
public function addBall(x:Number, y:Number, radius:Number):void { var bodyDef:b2BodyDef = new b2BodyDef(); bodyDef.position.Set((x + radius) / PIXELS_TO_METRE, (y + radius) / PIXELS_TO_METRE); bodyDef.type = b2Body.b2_dynamicBody; var content:Sprite = new Sprite(); content.graphics.beginFill(0x000000); content.graphics.drawCircle(0, 0, radius); bodyDef.userData = content; addChild(bodyDef.userData); var circShape:b2CircleShape = new b2CircleShape(radius / PIXELS_TO_METRE); var fixtureDef:b2FixtureDef = new b2FixtureDef(); fixtureDef.shape = circShape; fixtureDef.density = 1; ball = world.CreateBody(bodyDef); ball.CreateFixture(fixtureDef); }
ボールを作成することは、長方形を作成することと非常によく似ているため、これについては考えません。
はしごを持つ三角形を作成します。
public function addTriangle(x:Number, y:Number, size:Number):void { var bodyDef:b2BodyDef = new b2BodyDef(); bodyDef.position.Set(x / PIXELS_TO_METRE, y / PIXELS_TO_METRE); var content:Sprite = new Sprite(); content.graphics.beginFill(0x000000); content.graphics.moveTo(size, 0); content.graphics.lineTo(0, size); content.graphics.lineTo(size, size); bodyDef.userData = content; addChild(bodyDef.userData); var polyDef:b2PolygonShape = new b2PolygonShape(); polyDef.SetAsArray([ new b2Vec2(size / PIXELS_TO_METRE, size / PIXELS_TO_METRE), new b2Vec2(0, size / PIXELS_TO_METRE), new b2Vec2(size / PIXELS_TO_METRE, 0) ]); var fixtureDef:b2FixtureDef = new b2FixtureDef(); fixtureDef.shape = polyDef; fixtureDef.density = 0; var body:b2Body = world.CreateBody(bodyDef); body.CreateFixture(fixtureDef); }
物理モデルの作成を除き、ここではすべて同じです。 ここの物理モデルは、b2PolygonShapeタイプのオブジェクトです。 テンプレート(addBoxなど)はないため、ベクターの配列を使用して三角形を描画します。 カウントは、配列の最後の要素から最初の要素まで開始します。
次に、次のように記述するcreteObjectsという関数を作成します。
public function creteObjects():void { addBall(10, 400, 50); addBox(0, 580, 450, 20, 0); addBox(250, 540, 200, 40, 0); addTriangle(210, 540, 40); addBox(610, 540, 190, 60); addBox(-10, 0, 10, 600); addBox(800, 0, 10, 600); var m1:b2Body = addBox(430, 540, 20, 5, 0); var m2:b2Body = addBox(451, 540, 20, 5, 1); var m3:b2Body = addBox(472, 540, 20, 5, 1); var m4:b2Body = addBox(493, 540, 20, 5, 1); var m5:b2Body = addBox(514, 540, 20, 5, 1); var m6:b2Body = addBox(535, 540, 20, 5, 1); var m7:b2Body = addBox(556, 540, 20, 5, 1); var m8:b2Body = addBox(577, 540, 20, 5, 1); var m9:b2Body = addBox(598, 540, 20, 5, 0); }
最後の要素は私たちの未来の橋です。
次に、ブリッジの要素を接続する必要があります。
creteObjectsの最後に以下を記述します。
var jointDef:b2RevoluteJointDef = new b2RevoluteJointDef(); jointDef.enableLimit = true; jointDef.lowerAngle = 0; jointDef.upperAngle = 0.1; jointDef.Initialize(m1, m2, m1.GetWorldCenter()); world.CreateJoint(jointDef); jointDef.Initialize(m2, m3, m2.GetWorldCenter()); world.CreateJoint(jointDef); jointDef.Initialize(m3, m4, m3.GetWorldCenter()); world.CreateJoint(jointDef); jointDef.Initialize(m4, m5, m4.GetWorldCenter()); world.CreateJoint(jointDef); jointDef.Initialize(m5, m6, m5.GetWorldCenter()); world.CreateJoint(jointDef); jointDef.Initialize(m6, m7, m6.GetWorldCenter()); world.CreateJoint(jointDef); jointDef.Initialize(m7, m8, m7.GetWorldCenter()); world.CreateJoint(jointDef); jointDef.Initialize(m8, m9, m8.GetWorldCenter()); world.CreateJoint(jointDef);
まず、制限を適用するバンドルの構成を作成し、あまり揺れないようにします。
次に、すべての要素を接続します。
世界のすべてのオブジェクトは準備ができており、動作しています。 しかし、アプリケーションをコンパイルすると、良いものは見当たりません。 なんで? レンダリングしませんでした。
init関数の最後に、ENTER_FRAMEイベントを発生させます:
stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
実際にonEnterFrame関数のコード:
public function onEnterFrame(e:Event = null):void { world.Step(1 / 30, 10, 10); for (var bb:b2Body = world.GetBodyList(); bb; bb = bb.GetNext()){ if (bb.GetUserData() is Sprite) { var sprite:Sprite = bb.GetUserData() as Sprite; sprite.x = bb.GetPosition().x * PIXELS_TO_METRE; sprite.y = bb.GetPosition().y * PIXELS_TO_METRE; sprite.rotation = bb.GetAngle() * (180 / Math.PI); } } }
Step関数は世界を更新します。 パラメータとして、オブジェクトを更新する頻度がかかります。 数秒で。
次に、ワールド内のすべてのオブジェクトを取得し、それらの位置と回転を更新します。
テストできます。 私たちの性格を制御できないことを考慮せずに、すべてがうまく機能します。 今それを修正します。

キーストロークハンドラーを追加します。
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
onKeyDown関数を作成します。
public function onKeyDown(e:KeyboardEvent):void { if (e.keyCode == 39 && getTimer() - p > 200) { ball.ApplyImpulse(new b2Vec2(10, 0), ball.GetPosition()); p = getTimer(); }else if (e.keyCode == 37 && getTimer() - p > 200) { ball.ApplyImpulse(new b2Vec2( -10, 0), ball.GetPosition()); p = getTimer(); } }
ApplyImpulse関数は、指定された力ベクトルと位置でオブジェクトにプッシュを適用します。
また、キーストロークを覚えていましたが、次は200ミリ秒以内に発生します。
最後に、これを取得します。 ここからプロジェクトのソースをダウンロードしてください 。
Box2Dの世界におけるオブジェクトの作成について、標準と私たちの両方について簡単に説明しました。 彼らは靭帯を使って橋を作り、キャラクターに動きを教えました。 幸運を祈ります、親愛なる読者!