Box2DFlashAS3というライブラリについての話です。
初稿が2008年なので、2012年現在ではちょっと内容が古くなっていますが、円形(球形)重力を実現する方法は現在でも参考になると思います。やる気がある人は、ソースを取得して変更点を見比べながら修正・使用して下さい。
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のパッケージ名を強引に変更して、併用できるようにしてみました。
$ cd Box2DFlashAS3_2.0.1 # ライブラリを展開したフォルダへ移動 $ ruby txtcnv_Box2D.rb . BoxX2D # 対象にカレントフォルダを指定
Box2Dの重力は一方向への平面タイプだけですが、球形(円形)タイプがあると、いろいろゲームの方向性が広がります。
b2Worldクラスを継承した、RoundWorldクラスと、b2Islandクラスを継承したRoundIslandクラスを作りました。
但し、バージョン2.0.1専用となっています。なるべく依存度を低くしたかったのですが、ちょっと無理っぽいです。
なので、バージョンが上がるたびに書き換えていかなきゃなりません。(涙)
ダウンロードファイルを解凍して、RoundWorld.as、RoundIsland.asの2つのファイルを取り出します。
その2ファイルをBox2DのDynamicsフォルダ(b2World.asなどがあるフォルダ)に放り込んでください。
ちなみに各クラスのパッケージ名はBox2Dのままですので、パッケージネームを強制変更している場合は、上記、Rubyスクリプトを
もう一度実行してパッケージ名を変更してください。
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クラスまで継承したくなかったので、こんな感じになっています。