2009.8.31
Box2D(Box2DFlashAS3)によるActionScript物理シミュレーション

●第3回:静体の生成

◆「物体」について

Box2Dでシミュレーションに使用するオブジェクトを、本記事では「物体」と呼びます。
物体には、動くことのない固定されたものと何らかの力を受けて動くものがあります。本記事では固定された物体を「静体」、動ける物体を「動体」と呼びます。
物体は静体・動体ともb2Bodyクラスのオブジェクトです。
b2Bodyオブジェクトを生成するには、b2BodyDefオブジェクトが必要になります。加えて、形状を定義するためにb2ShapeDefオブジェクト(※1)も必要になります。

これらのオブジェクトでは次のような設定を行えます。
b2BodyDefオブジェクト:

  • 物体の初期位置
  • 初期回転角度
  • 速度の減衰率
  • 回転速度の減衰率ほか

b2ShapeDefオブジェクト:

  • 形状(※2)
  • 密度(質量に関係)
  • 摩擦係数
  • 反発係数ほか

b2BodyDefオブジェクトを元に物体を表すb2Bodyオブジェクトを作成し、その後b2ShapeDefオブジェクトから形状を表すb2Shapeオブジェクトを作成します。
今回は先にb2BodyDefオブジェクトとb2ShapeDefオブジェクトを生成し、その後b2Bodyオブジェクトの生成と形状の作成を行っていきます。
以下、実際に長方形の静体を作成してみます。この長方形は他の物体を乗せる床にあたるものになります。

◆静体の作成

後述しますが、Box2Dの2.0.2では物体はデフォルトでは静体として作成されます。そして静体にプラスαの情報を加えたものが動体となります。なのでまず静体の作成方法をしっかり理解しておく必要があります。

・b2BodyDefオブジェクトの生成

b2BodyDefオブジェクトの生成にはb2BodyDefコンストラクタを実行します。b2BodyDefオブジェクトには静体の座標位置を指定します。
座標位置の指定にはb2BodyDef.positionプロパティを使用します。

【コンストラクタ】b2BodyDef()-b2BodyDefオブジェクトの生成
【P】b2BodyDef.position:b2Vec2-物体の初期座標位置

位置を指定するにあたって、ムービークリップインスタンスであればシンボルに設定した基準点の座標を指定することになりますが、Box2Dで扱う物体の場合はどの位置を基準とするのでしょうか。
基本的にはその物体の形状の中心になります。つまり、円や長方形であれば明白に中心の位置が基準となり、その他の多角形の場合は頂点のX、Y各座標位置の平均の位置が基準となります。
今回のスクリプトは、前回のファイル(Box2D_02_01.as)に追加する形になります。まずは追加するスクリプトコードのみ記載して、後で必要に応じて全体を掲載します。

スクリプト:3-1

・インポートのセクションに追加

import Box2D.Dynamics.b2BodyDef;

・コンストラクタの最後尾に追加

//▼床(静体)の生成
//BodyDefの設定

var bdFloor:b2BodyDef = new b2BodyDef();
bdFloor.position.Set(5.5 / 2, 3);

b2BodyDef.positionプロパティはデフォルトでx=0、y=0のb2Vec2オブジェクトが割り当てられるので、b2Vec2.Set()メソッドで設定しています。ピクセル位置で考えるとX座標はステージ幅(550)の中間位置、Y座標は300でステージの下方となります。

・b2ShapeDefオブジェクトの生成

長方形を作るにはb2ShapeDefクラスのサブクラスであるb2PolygonDefクラスを使います。
形状はb2PolygonDef.SetAsBox()メソッドで指定します。

【コンストラクタ】b2PolygonDef()-b2PolygonDefオブジェクトの生成
【M】b2PolygonDef.SetAsBox(hx:Number, hy:Number) : void-物体としての長方形を定義

引数-hx:横サイズの半分(メートル)/hy:縦サイズの半分(メートル)
戻り値-なし

b2PolygonDef.SetAsBox()メソッドでは横縦サイズの半分のサイズを指定します。今回は幅4m高さ0.3mの板を作ろうと思うので、次のスクリプトを追加します。

スクリプト:3-2

・インポートのセクションに追加

import Box2D.Collision.Shapes.b2PolygonDef;

・コンストラクタの最後尾に追加

//ShapeDefの設定
var pdFloor:b2PolygonDef = new b2PolygonDef();
pdFloor.SetAsBox(2, 0.15);

これで次の画像のような静体を作る設定ができました。

静体(床)の設定内容

・b2Bodyオブジェクトの生成

b2BodyDefオブジェクトとb2ShapeDefオブジェクト(今回はb2PolygonDefオブジェクト)を用意できたのでb2Bodyオブジェクトを生成します。
b2Bodyオブジェクトの生成はコンストラクタではなくb2WorldクラスのCreateBody()メソッドで行います。これは、b2Worldオブジェクトがその物理ワールド内に作成された全てのb2Bodyオブジェクトを子として管理するためです。
形状を作成しb2Bodyオブジェクトに適用するにはb2BodyクラスのCreateShape()メソッドを使います。

【M】b2World.CreateBody(def:b2BodyDef) : b2Body

引数-def:物体に反映する情報を持ったb2BodyDefオブジェクト
戻り値-生成されたb2Bodyオブジェクト

【M】b2Body.CreateShape(def:b2ShapeDef) : b2Shape

引数-物体に適用するb2ShapeDefオブジェクト
戻り値-生成されたb2Shapeオブジェクト

全ての物体(b2Bodyオブジェクト)が物理ワールド(b2Worldオブジェクト)に子として管理されるのと同様に、ある物体に適用された形状(b2Shapeオブジェクト)もその物体の子として管理されます。
Box2Dの2.0.0では静物のb2Bodyオブジェクトを生成するためにb2World.CreateStaticBody()メソッドが、動体のb2Bodyオブジェクトを生成するためにb2World.CreateDynamicBody()メソッドが用意されていました。これが2.0.2ではCreateBody()メソッドに統一されています。
物体の生成については他の部分はあまり大きな変更は無いようなので、2.0.0のサンプルコードを2.0.2で使う場合、物体の生成に関してはCreateStaticBody()メソッド/CreateDynamicBody()メソッドをCreateBody()メソッドに書き換えれば動作すると思います。

スクリプト:3-3

・インポートのセクションに追加

import Box2D.Dynamics.b2Body;

・コンストラクタの最後尾に追加

//ボディの生成
var bFloor:b2Body = _world.CreateBody(bdFloor);
bFloor.CreateShape(pdFloor);

床の静体は基本的に他所から参照する予定は無いのでローカル変数で扱います。
今回は形状(b2Shapeオブジェクト)をプログラム上で特に扱う予定は無いのでCreateShape()メソッドで返された値は参照を保持しません。
ここまでのスクリプト全体は次のようになります。なお、前回のスクリプト【スクリプト:2-2】(Box2D_02_01.as)からの追加部分は青く表示してあります。また、ドキュメントクラス名の変更に伴い修正してある部分を赤く表示してあります。

スクリプト:3-4

//Box2D_03_01.as
package {
    //▼インポート
    import flash.display.Sprite;
    import Box2D.Collision.b2AABB;
    import Box2D.Common.Math.b2Vec2;
    import Box2D.Dynamics.b2World;
    import Box2D.Dynamics.b2BodyDef;
    import Box2D.Collision.Shapes.b2PolygonDef;
    import Box2D.Dynamics.b2Body;


    public class Box2D_03_01 extends Sprite {
        //▼プロパティ定義
        private var _world:b2World;
        //▼コンストラクタ定義
        public function Box2D_03_01() {
            //▼物理エンジンのセットアップ
            //物理エンジン適用範囲の設定(ステージの100ピクセル外側)

            var worldRegion:b2AABB = new b2AABB();//矩形作成
            worldRegion.lowerBound.Set(-1, -1);
            worldRegion.upperBound.Set(6.5, 5);
            //重力の設定
            var gravity:b2Vec2 = new b2Vec2(0, 9.8);
            //範囲・重力・スリープの有無を指定して物理ワールドを作成
            _world = new b2World(worldRegion, gravity, true);

            //▼床(静体)の生成
            //BodyDefの設定

            var bdFloor:b2BodyDef = new b2BodyDef();
            bdFloor.position.Set(5.5 / 2, 3);

            //ShapeDefの設定
            var pdFloor:b2PolygonDef = new b2PolygonDef();
            pdFloor.SetAsBox(2, 0.15);

            //ボディの生成
            var bFloor:b2Body = _world.CreateBody(bdFloor);
            bFloor.CreateShape(pdFloor);

        }
    }
}

このスクリプトでは表示に関する設定がないので、生成した床はまだ表示されません。
次は動体を作成します。その後に表示に関する設定を行っていこうと思います。

→今回のファイル【Box2D_03_01.zip

※1.実際に作成するのは、b2ShapeDefクラスのサブクラスであるb2PolygonDefクラスかb2CircleDefクラスのオブジェクトになります。
作成できる物体の形状は多角形か円で、多角形はb2PolygonDefオブジェクトを、円はb2CircleDefオブジェクトを作成します。
この辺りについてはいずれあらためて触れます。

※2.形状については、前述のb2PolygonDefクラス・b2CircleDefクラスのプロパティやメソッドで設定します。

物体の位置の指定はb2Bodyオブジェクトの生成後にb2Bodyクラスのメソッドでも行えますが、b2BodyDefオブジェクトで予め指定しておくのがパフォーマンス的に優れているようです()。

ある物体には複数の形状が適用する場合があります。例えば雪だるまのような形の物体を作りたい場合には、2つの円の形状を物体に適用することになります。

このサイトへのご意見・ご感想は[takuya@haphands.com]までお願いします!