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

●第2回:物理ワールドのセットアップ

◆「物理ワールド」について

Box2Dによる物理シミュレーションを行うには、まず「物理ワールド」を準備します。
物理ワールドは「シミュレーションの適用範囲」「重力」「スリープの有効・無効」(※1)を設定したb2Worldクラスのオブジェクトです。
b2Worldオブジェクトの生成に必要なこれら3つの情報について以下見ていきます。

・シミュレーションの適用範囲

シミュレーションの適用範囲は矩形で指定します。通常のActionScriptならRectangleクラスを使いそうなところですが、Box2Dの矩形範囲指定はb2AABBクラス(※2)を使います。b2AABBクラスによる矩形は、b2AABBオブジェクトを作成後に以下のプロパティにより左上と右下の座標を設定することで決定します。

【コンストラクタ】b2AABB()-b2AABBオブジェクトの生成
【P】b2AABB.lowerBound:b2Vec2-矩形の左上の座標
【P】b2AABB.upperBound:b2Vec2-矩形の右下の座標

座標の指定はb2Vec2クラスを使います。b2Vec2クラスはActionScript3.0のPointクラスに似たクラスでxプロパティ、yプロパティを持っています。
b2AABB.lowerBoundプロパティ、b2AABB.upperBoundプロパティにはx、yが0のb2Vec2オブジェクトがデフォルトで設定されているので、b2Vec2.Set()メソッドで座標を設定します。

【M】b2Vec2.Set(x:Number=0, y:Number=0) : void-座標位置を設定

引数-x:水平位置(メートル)/y:垂直位置(メートル)
戻り値-なし

Box2Dの座標などの指定で重要なのは、長さの単位がピクセルではなくメートルであるという点です(※3)。
画面上で1mをどのぐらいの長さとして表示するかは、プログラマが自由に決められます。
今回は1m=100ピクセルとして扱おうと思います。この値は物理シミュレーションの結果を表示する処理で必要になります。よって実際にスクリプトコード中に登場するのはもう少し先になります。
今回はステージサイズ550×400ピクセル(5.5m×4m)で作成します。物理ワールドはステージを外側に100ピクセル(1m)広げた領域として設定します。
以下、「Box2D_02_01」という名前のドキュメントクラスにスクリプトを記述していきます。
まず、範囲の設定まで記述してみます。

スクリプト:2-1

//Box2D_02_01.as
package {
    //▼インポート
    import flash.display.Sprite;
    import Box2D.Collision.b2AABB;

    public class Box2D_02_01 extends Sprite {
        //▼コンストラクタ定義
        public function Box2D_02_01() {
            //▼物理エンジンのセットアップ
            //物理エンジン適用範囲の設定(ステージの100ピクセル外側)
            var worldRegion:b2AABB = new b2AABB();//矩形作成
            worldRegion.lowerBound.Set(-1, -1);
            worldRegion.upperBound.Set(6.5, 5);
        }
    }
}

適用範囲

・重力

重力は物理ワールドに適用される力で、b2Vec2オブジェクトで指定します。
重力の単位はm/s2(メートル毎秒毎秒)となります。重力加速度は約9.8m/s2なので、b2Vec2オブジェクト生成時にコンストラクタの引数でxを0に、yを9.8に設定します。

【コンストラクタ】b2Vec2(x:Number=0, y:Number=0)-b2Vec2オブジェクトの生成

引数-x:水平位置(メートル)/y:垂直位置(メートル)

・スリープの有効・無効

スリープの有効・無効の設定はブール値で指定します。trueはスリープを有効に、falseは無効にすることを表します。
物理ワールド生成時のスリープ設定は物理ワールド内の全てのオブジェクトに対して有効な設定ですが、個々のオブジェクトに関するスリープ設定もありますが、それは後の回で触れようと思います。
特別な事情がない限り、スリープは有効にしておくのがよいでしょう。

前述の通り、物理ワールドはb2Worldクラスで表されます。範囲、重力、スリープの有効・無効に関する設定を引数としてb2World()コンストラクタを実行します。
範囲は先ほど作成したb2AABBオブジェクト(変数worldRegion)を指定します。

【コンストラクタ】b2World(worldAABB:b2AABB, gravity:b2Vec2, doSleep:Boolean)-b2Worldオブジェクトの生成

引数-worldAABB:シミュレーション領域を表すb2AABBオブジェクト/gravity:シミュレーション領域に常時かかる力(重力)を表すb2Vec2オブジェクト/doSleep:スリープの有効・無効を表すブール値

スクリプト2-1にプラスして物理ワールドの生成までを完了させます。スクリプト2-1からの追加部分は青く表示してあります。

スクリプト:2-2

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

    public class Box2D_02_01 extends Sprite {
        //▼プロパティ定義
        private var _world:b2World;
        //▼コンストラクタ定義
        public function Box2D_02_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);
        }
    }
}

なお、物理ワールドはいくつかのメソッドから参照することになるので、プライベートプロパティ_worldとして定義してあります。
このクラス定義ファイルはドキュメントクラスとして使用します。ただ、現時点ではムービープレビューを実行しても目に見える処理は行われません。
次回はシミュレーションに使用するオブジェクトを生成し、表示するところまでいこうと思います。

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

※1.「スリープ」とは、オブジェクトにかかる力が減衰し停止状態になったときにシミュレーションの計算から外す設定のことです。

※2.「AABB」とは「Axis Aligned Bounding Box」の略で「軸に並行な直方体」ぐらいの意味のようです。3D演算などで使われる用語っぽいですが、Box2DはX軸、Y軸の2D用のシミュレーションを行います。

※3.Box2Dは0.1m~10m程度のサイズのオブジェクトで適切に動作するよう調整されています。
ちなみに、長さの単位がメートルなのは便宜上のことだと思うので、基本的にはBox2Dの計算に使う独自の尺度があるのだと理解しておけばよいかと思います。
例えば、あるプロジェクトで50mと30mのオブジェクトを作りたい、という場合には5mと3mのオブジェクトを作成して50mと30mのオブジェクトと思い込めばよいと思います。この場合、「今回のプロジェクトでは単位を10倍(10m)で考えよう」といった具合になります。

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