このエントリーをはてなブックマークに追加

Box2Dアレコレ for Flash

Box2DFlashAS3というライブラリについての話です。
初稿が2008年なので、2012年現在ではちょっと内容が古くなっていますが、円形(球形)重力を実現する方法は現在でも参考になると思います。やる気がある人は、ソースを取得して変更点を見比べながら修正・使用して下さい。

バージョン2.0.1。二転三転する仕様変更

Box2DFlashAS3(以下Box2D)はバージョン1.4.3から2.0.0になって、クラス内の関数に大きく変更がなされました。 しかし、変更箇所の詳しい情報がほとんど無く、Forumにもほとんど情報が載っていないので、基本はソースを追いかけることになります。
仕様変更の流れは、しばらく続きそうです。というのも、b2WorldクラスのCreateStaticBody()、CreateDynamicBody()が CreateBody()に集約されましたが、1.4.3の時は、もともとCreateBody()に集約されていたのに対し、 2.0.0でCreateStaticBody()、CreateDynamicBody()に2分されるという経緯があり、その他にも、これまでの流れからすると?と 付きそうな仕様変更がまま見られたからです。 2.0.1では、b2BodyクラスのGetContactList()が無くなって、m_contactListメンバ変数から直接アクセスするしかなくなった仕様変更も謎です。 高速化の意味合いが強いのでしょうが、もともとpublicなメンバ変数でしたし、過去のプログラムを動かなくしてまで関数を無くす必要性があったのでしょうか。

パッケージネームを強制変更して使う

そんな訳で、ライブラリを複数バージョン使用できる開発環境が欲しくなります。
Box2Dライブラリのパッケージ名は"Box2D"で、現在、1.4.3から2.0.1まで同じ名前です。 僕はFlash開発にFlash CS3(以下CS3)を使用しているのですが、ライブラリの検索パス(クラスパス)は、 CS3の環境設定から行い、リストの上にあるものから優先して使用されます。こうなると、同じパッケージ名だと 不都合が出てしまいます。(こういう時は、みなさんどうしているのでしょうか? プログラム単位でライブラリ検索パスを 変更できないものでしょうか?)
CS3側の設定で解決できるのか分からなかったので、緊急対策として、2.0.1のパッケージ名を強引に変更して、併用できるようにしてみました。

変更方法は以下のような感じになります。
全ソースファイルを手で編集するのは現実的ではないのでRubyスクリプトを用意しました。 スクリプトは物理のかぎしっぽさんの ところにあったものを参考にさせて頂きました。ほとんどそのままですけど。
使い方は、ターミナルなどで、ライブラリのソースファイルのあるフォルダの中に入り、
$ cd Box2DFlashAS3_2.0.1         # ライブラリを展開したフォルダへ移動
$ ruby txtcnv_Box2D.rb . BoxX2D  # 対象にカレントフォルダを指定
などとします。対象ファイルを直接書き換えますので、くれぐれも、ご自分の責任の上でご使用ください。

それから変更するパッケージ名ですが、"Box2D2"などとすると、2回連続で同じ条件でRubyスクリプトを実行すると、 また、"Box2D"の部分が置換されて、"Box2D22"となってしまうので注意してください。

地球は丸かった。RoundWorldクラスの作成

Box2Dの重力は一方向への平面タイプだけですが、球形(円形)タイプがあると、いろいろゲームの方向性が広がります。

b2Worldクラスを継承した、RoundWorldクラスと、b2Islandクラスを継承したRoundIslandクラスを作りました。 但し、バージョン2.0.1専用となっています。なるべく依存度を低くしたかったのですが、ちょっと無理っぽいです。 なので、バージョンが上がるたびに書き換えていかなきゃなりません。(涙)

ダウンロードファイルを解凍して、RoundWorld.as、RoundIsland.asの2つのファイルを取り出します。
その2ファイルをBox2DのDynamicsフォルダ(b2World.asなどがあるフォルダ)に放り込んでください。
ちなみに各クラスのパッケージ名はBox2Dのままですので、パッケージネームを強制変更している場合は、上記、Rubyスクリプトを もう一度実行してパッケージ名を変更してください。

RoundWorld使い方

b2Worldの代わりに、RoundWorldをインスタンス化します。重力の中心点を設定する以外は、b2Worldと同じです。

// 重力の中心点
var gPos:b2Vec2 = new b2Vec2(PLANET_X/physc,PLANET_Y/physc);
// 重力の強さ。Yの設定だけが有効。マイナスにすると重力の中心点から物体が遠ざかります
var gravity:b2Vec2 = new b2Vec2(0.0, 50.0/physc);
// ワールド作成
var world:RoundWorld = new RoundWorld(worldAABB,gravity,gPos,doSleep);

重力の中心点の設定にnullを与えると、通常の重力モードと同じになります。

var world:RoundWorld = new RoundWorld(worldAABB,gravity,null,doSleep);

おまけ機能

2.0.0からデバッグ描画機能がb2Worldクラスの中に組み込まれました。便利なんですけど、ボディ単位で描画のON/OFFが できないので、おまけ機能でRoundWorldクラスに実装してみました。

var dbgDraw:b2DebugDraw = new b2DebugDraw();
dbgDraw.m_sprite = shape_mc;
dbgDraw.m_drawScale = physc;
dbgDraw.m_fillAlpha = 1.0;
dbgDraw.m_lineThickness = 1.0;
dbgDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit;
world.SetDebugDraw(dbgDraw);
            :
var body:b2Body = world.CreateBody(def);
body.m_flags |= 0x8000;    // このボディのデバッグ描画をスキップ

0x8000などと、直値で申し訳ないですが、b2Bodyクラスまで継承したくなかったので、こんな感じになっています。