cocos2dにBox2dを組み込む.
Box2dとは物理演算をシュミレートしてくれるエンジンです。ゲーム開発には必須の衝突、摩擦、加速度とかいろいろシュミレートしてくれます。元々はFlashのAction Scriptとかに組み込んで使われてたみたいですが、cocos2dのフレームワークにC++で書かれたライブラリーが入っています。
僕がcocos2dを選んだのは結局Box2dを使いたかったに過ぎないです。
ちなみにcocosにはBox2dの他にchipmunkという物理エンジンも組み込まれています。違いはBox2dがC++ライブラリなのに対し、chipmunkはC言語で書かれたライブラリーだという事です。chipmunkの方はあまり詳しくないので、どちらがいいかは知りません。使いやすい方を選べばいいと思います。
という事で僕はBox2dで作っていきます。ま、組み込むのは簡単です。テンプレートにオプションがあるので、プロジェクト作成時に’cocos2d iOS with Box2d’を選んでやるだけです。
あとはプロジェクト名などを他のプロジェクト作成時と同じように決めてCreateするだけです。
>cocos2dのプロジェクトを作成する方法。
こんな感じで実行できます。
cocosだけの時とは違い、’GLES-Render’と’PhysicsSprite’というファイルが追加されています。また、ファイルの拡張子も.mから.mmになっています。
まずGLES-Renderファイルですが、これはデバッグ時にオブジェクトのバウンディングボックスを描画したり、ヒット認識しているかどうかを視覚的に描画してくれるクラスが実装されているみたいです。
PhysicsSpriteはcocos2dのスプライトとBox2dのオブジェクトをつなぐ役割をしているみたいです。ポジションや角度をcocos2dの座標系に変換しています。
.mmファイルはObjective-CとC++を混在して書くことができるファイルです。Box2dはC++で書かれているので、こちらの形式が必要になります。また開発において違うクラスを追加する場合、ヘッダファイルにC++で書かれたファイルをインポートするときは、それらのファイルも.mm拡張子にしなければなりません。IntroLayerやAppDelegateが.mmになっているのもそれが理由です。
では、通常のcocos2dテンプレートとの中身の違いを簡単に見て行きましょう。
HelloWorldLayer.mmを開きます。
@interface HelloWorldLayer() -(void) initPhysics; -(void) addNewSpriteAtPosition:(CGPoint)p; -(void) createMenu; @end
ここはクラスエクステンションが書かれています。プライベートメソッドを定義する部分ですが、今は気にしなくていいです。
次にイニシャライザ(init)です。大まかな流れとしては、
- タッチ、加速度センサーの有効化
- シミュレータの初期化(initPhysics)
- メニューを作成(createMenu)
- ボックスに使われる画像テクスチャを登録
- 登録したテクスチャを使いオブジェクトを作り、そのオブジェクトにヒットをもたせる(addNewSpriteAtPosition)
- ‘Tap Screen’テキストの配置
- シュミレータをスタート(scheduleUpdate)
イニシャライザもかなり違いますが、特に難しいことはしていません。基本的に必要なのは
[self initPhysics]; [self scheduleUpdate];
です。initPhysicsは物理演算が適応される世界を作ってくれています。重力や、スペースの壁なんかが定義されています。scheduleUpdateはフレーム毎に呼び出されるcocosのスケジューラです。これを回し続けることで、オブジェクトの位置や速度をシミュレートします。
その他のメソッドは基本的には不要です。アプリによって不要な呼び出しを消していけばいいです。
createMenuメソッドはメニューを配置し、アクションを定義している部分です。ここはすべてcocos2dのライブラリが用いられているだけです。今は割愛します。
initPhysicsが次に書かれています。もうワールドが作られているので、あとは重力などのパラメータをいじるだけですが、実はデバッグ時に必要なヒットの描画もここで設定されています。
uint32 flags = 0; flags += b2Draw::e_shapeBit; // flags += b2Draw::e_jointBit; // flags += b2Draw::e_aabbBit; // flags += b2Draw::e_pairBit; // flags += b2Draw::e_centerOfMassBit; m_debugDraw->SetFlags(flags);
この部分を簡単に解説すると、
‘e_shapeBit’はオブジェクトのポリゴンの形を描画します。
‘e_jointBit’はオブジェクト同士の連結部分の描画。
‘e_aabbBit’はオブジェクトのバウンディングボックスを包括するような座標軸でできた四角形を書きます。
‘e_pairBit’はオブジェクトのペア関係の線を描画します。
‘e_centerOfMassBit’は質量の中心を描画します。
すべてをコメントアウトすれば、Box2dのデバッグ描画はされません。
次の’draw’メソッドで上記のデバッグオブジェクトを描画しています。
次に書かれているのが’addNewSpriteAtPosition’メソッドです。テクスチャからランダムに’A’ 、’B'、’C'、’D'の部分を切り出しオブジェクトを作っています。
作ったオブジェクトにbox2dのbodyを割り当て、b2FixtureDefクラスを用い、密度や跳ね返りを定義しています。
その下の’update’メソッドが、毎フレームごとに呼ばれる部分です。
int32 velocityIterations = 8; int32 positionIterations = 1;
を設定することで、シミュレートの正確さを調整できます。多ければ多いほど正確なシミュレートができるのですが、もちろんCPUに負担がかかります。上記の値がBox2dの推奨値とされています。
最後に’ccTouchesEnd’。タッチが離れた時に呼び出されます。中で’addNewSpriteAtPosition’を呼び出しているので、タッチごとにボックスを生成することができます。
こんな感じでざっとBox2dを組み込んだcocos2dのテンプレート内容を解説してみました。ちょっと長くなってまったな…。