Box2DでActionScript物理プログラミング

第2回 物理エンジンをセットアップし,箱を落とすFlashを作る

この記事を読むのに必要な時間:およそ 4 分

箱の設置

床の次は箱です。物体をワールド内に設置する流れは同じですが,内容が少し違います。

箱の場所とサイズ

箱の場所とサイズ

箱の場所を定義する

床のときと同じように,b2BodyDefを使って箱の場所を定義します。

var bodyDef:b2BodyDef = new b2BodyDef();
bodyDef.position.Set(2.5, 1);

箱は,左から2.5m,上から1mの位置から落とします。この書き方は床のときとまったく同じです。ここでの「上から」というのは画面の上端から1mという意味です。床は上から3mの高さにあるので,箱は床の上から2mの位置にあることになります。

箱の形を定義する

箱の形は,床のときとは違って少し傾いています。

var shapeDef:b2PolygonDef= new b2PolygonDef();
shapeDef.SetAsOrientedBox(0.3, 0.2, new b2Vec2(0, 0), 0.8);

使っているメソッドがSetAsBoxからSetAsOrientedBoxに変わっています。SetAsBoxを使うと「まっすぐな長方形」が作れますが,SetAsOrientedBoxを使うと「傾いた長方形」が作れます。

SetAsOrientedBoxの引数ですが,最初の2つはSetAsBoxと同じく,長方形の幅と高さの半分の値です。3つ目の引数には,b2Vec2を使って回転させるときの中心座標を指定します。長方形の真ん中を中心に回転させるときは,(0, 0)を指定してください。4つ目の引数には,長方形を傾ける角度をラジアン単位で指定します。時計回りの方向がプラスです。0.8とすれば,大体45度回ります。

箱の重さを設定する

床のときは形まで設定してしまえばワールドへの設置が出来ましたが,箱の場合はまだ続きます。まずは重さ(密度)を設定します。

shapeDef.density = 1;

densityは密度のことです。これを1にすると,大きさが1平方メートルの物体の重さが1キログラムとなります。今回作った箱の大きさは0.24平方メートルなので,重さは0.24キログラムです。かなり軽い箱だといえます。

この値を変えることで箱の重さを定義できるのですが,今回のサンプルでは意味がありません。ガリレオ・ガリレイがピサの斜塔で行った実験から分かるとおり,箱が重くても軽くても,落ちるスピードは一定だからです。重さが意味を持つようになるのは,動く物体同士がぶつかったときですが,それは別の機会に説明します。

箱の反発係数を設定する

最後に,反発係数restitutionを設定します。反発係数とは,物体が何かにぶつかったときにどれだけ跳ね返るかを表す数値です。

shapeDef.restitution = 0.2;

反発係数を0.2にすると,床で少しバウンドして落ち着くような動作になります。反発係数は,値が大きいほどその効果を発揮します。0にするとまったくバウンドしません。逆に1にするといつまでもバウンドし続けます。このような物体は普通は存在しないので,大抵は反発係数を0に近いあたりで設定します。

ちなみにこれを1以上にすると,まるでトランポリンのように,落とし始めた高さ以上にバウンドします。こうすると大抵は物体の速度がどんどん上がっていき,収集がつかなくなってしまいます。

箱を設置する

パラメータの設定が終わったので,箱をワールド内に設置します。

var body:b2Body = world.CreateDynamicBody(bodyDef);
body.CreateShape(shapeDef);
body.SetMassFromShapes();

箱はワールド内で動き回るので,CreateDynamicBodyを使います。床でCreateStaticBodyを使ったのと対照的です。その次のCreateShapeで形を設定した後,SetMassFromShapesで重さを設定します。指定した密度はここで反映されます。

DebugDrawの設定

ようやく床と箱を設置できたところで,次はそれらを描画する設定をします。前回述べたとおり,Box2Dには物理エンジンによるシミュレーション結果を画面に表示するための機能が備わっています。今からその設定を行います。

var debugDraw:b2DebugDraw = new b2DebugDraw();
debugDraw.m_sprite = this;
debugDraw.m_drawScale = 100; // 1mを100ピクセルにする
debugDraw.m_fillAlpha = 0.3; // 不透明度
debugDraw.m_lineThickness = 1; // 線の太さ
debugDraw.m_drawFlags = b2DebugDraw.e_shapeBit;
world.SetDebugDraw(debugDraw);

b2DebugDrawがBox2Dが持つ描画システムです。不透明度や線の太さなど,色々な値を設定していますが,最も重要なのはm_drawScaleです。m_drawScaleは,物理エンジン内の1mを画面上の何ピクセルとして表すかを示す値です。

最初のほうで,画面全体のサイズを幅5m,高さ3.75mとすると書きましたが,そうなる理由がここにあります。mxmlcで作られるFlashのサイズは,何も指定しなければ幅が500ピクセル,高さが375ピクセルとなります。1mが100ピクセルということは,幅が5m,高さが3.75mになります。

物理エンジン内の時間を進める

ようやく全ての初期化が終わりました。後は物理エンジン内の時間を進める処理を書くだけです。Stepメソッドを呼び出すことで,物理エンジン内の時間を進めることが出来ます。

world.Step(1 / 24, 10);

1つ目の引数には,進める時間を秒単位で指定します。mxmlcで作られるFlashはデフォルトで秒間24フレームなので,1フレームで1/24秒だけ時間を進めます。

2つ目の引数には,物理エンジンのシミュレーション精度を指定します。値が大きいほど精度が上がりますが,その分時間もかかります。Box2Dのマニュアルには,10を指定するのがいいだろうと書かれているので,それに従います。

まとめ

これで今回のサンプルプログラムの説明が終わりました。プログラミングは実際に手を動かして学習したほうが理解が深まるので,是非サンプル中の数値を適当に書き換えて実行してみてください。そうすることで,それぞれの数値がサンプルFlash内のどこに影響しているか,実際に目で見て確認できます。

次回は,マウスのクリックに反応するような,もっと遊べるFlashに挑戦します。

著者プロフィール

木村秀敬(きむらひでたか)

茨城高専,北陸先端大を卒業後,独立系ベンチャーにあこがれてjig.jpに就職。 ActionScript好きですが,根はコテコテのC/C++プログラマです。Flash/ActionScriptに興味のある方は是非Spark Projectへ。