物理エンジンBox2Dについて軽く調べた

ふときっかけで物理エンジンのBox2Dについて少し調べたのでメモをば.

Box2Dって何?

http://www.box2d.org/manual.html

Box2D is a 2D rigid body simulation library for games. Programmer's can use it in their games to make objects move in believable ways and make the world seem more interactive. From the game's point of view a physics engine is just a system for procedural animation. Rather than paying (or begging) an animator to move your actors around, you can let Sir Isaac Newton do the directing.

簡単にいえば,2Dで剛体(形と質量のある物体)の物理的なシミュレーションを行うためのライブラリのことです.
たとえばゲーム製作で「四角い箱がいっぱい降ってきて,ある条件でぶつかり合うと消えてくれるようなゲームを作りたい」,なんてとき,自分で四角い箱同士の衝突判定や力学的な動作を再現しようとするととても気が遠くなってしまうのですが,そういうときにこのライブラリを利用すると(自分で0からすべて書くよりは)楽に実装できる,といった代物です.


もともとはC++で書かれていたライブラリなのですが,現在ではActionScript, Java, C#, Pythonなど,様々な言語に移植されているようです.


物理エンジンなので使うにはある程度物理の知識が必要になります.が,恐らく高校の力学の知識+α程度があれば十分だと思います.

実際にどういうものが作られているのか


http://box2dflash.sourceforge.net/
↑にFlashのサンプルがあるので,試してみると楽しいです.

何ができるのか

Box2Dは剛体の力学的な動作をシミュレートします.細かいところまでどういう設定ができるのか挙げると下のようになるかと.

  • 重力の強さの設定
    • 無重力や上向きの重力を設定できる
  • 「質量」の設定
  • 「摩擦」の設定
    • 静止摩擦力と動摩擦力は常に同じ値が割り当てられる
  • 「はね返り係数」の設定 (英語ではrestitution)
  • 剛体の形の設定
  • 制約条件
    • 2つの物体は棒で繋がれている だとか,2つの物体は1点のピンで固定されている といった条件を加えられる.
  • 衝突判定
  • 剛体の消去
  • 剛体の速度を変える,力を加える,衝撃を加える,といった動作
  • 動かない剛体
    • 壁や地面のようなもの

色々抜け落ちてると思うけど大雑把に挙げるとこんなもんでしょう.

何ができないのか

逆に,工夫すれば多分できるけど標準ではできないことは以下のようになるでしょう.

  • 風の再現
  • 「浮力」をもつ水中の再現
  • 均質でない密度をもつ剛体の再現
  • 凸でない形の剛体
    • 凸じゃないといけないらしい

これらは標準では実装されていないため,衝突判定や座標判定によって自分である程度のコードを書いたり,あるいは適当な剛体を組み合わせて再現する必要があります.
工夫すれば多分できますが,標準ではできないので注意.

実装に関する概念的なこと

プログラムに組み込んで使う場合にあたって.
実際にコードをどういう風に書くかということはちょっと面倒なので下の解説サイトに任せるとして,ここでば大雑把な構造だけ取り上げます.


Box2Dには大体以下の5つのクラスがあります.

  • World
  • Body
  • Shape
  • Joint
  • Contact
World

Worldはシミュレーション上の1つの「世界」を表します.
すべての剛体はWorldのクラスに登録されることになります.
Worldでは以下のようなことが設定できます.

  • 重力ベクトル
  • 世界の境界(適当に大きい値を指定する)
Body

Bodyは名の通り「剛体」です.
クラスを作成し,Worldに登録することで実際にシミュレートできるようになります.
様々なパラメータやメソッドがありますがここでは省略.

Shape

Shapeは剛体の幾何的な「形」を現すクラスで,Bodyを作る際に用いられます.
多角形や円があります.
多角形のShapeを作る際,引数となる点列は凸でかつ半時計回りで並んでいなければならないことに注意.

Joint

Jointは剛体同士の「制約条件」を表すクラスです.
Worldクラスに剛体を指定して登録することで,制約条件を指定できます.
Jointには以下の6つが用意されている模様.

  • Distance Joint
    • 2つの剛体間の距離を常に一定に保つ.堅い棒で繋がれたような状況を再現できる.
  • Revolute Joint
    • 2つの剛体を1つのピンで固定したような感じにする.2つの剛体の相対位置の自由さは失われ,回転の自由度だけが残る.
    • 回転する角度に制限を設けることが可能.
  • Prismatic Joint
    • 2つの剛体の向きを固定する.ピストンで固定されたような感じになる.
  • Pulley Joint
    • 滑車のひものようなものを再現.
    • 点Aから剛体1の距離 + 点Bから剛体2の距離 が常に一定となるような制約を加える.
  • Gear Joint
    • 歯車のようなものを再現したいときに使うらしい(←よく読んでないので知らない)
  • Mouse Joint
    • マウスで剛体を操作できるようになるらしい.
    • デバッグ用とのこと.
    • デバッグ用だけど実用にも使えるとかなんとか.
Contact

Contactは「衝突判定」を捕獲するクラスです.
概念上はContactですが,実際使う場合はContactListenerという名前を使います.
実装が少しややこしい感じになっていて,これを実際に使うには,

  • ContactListenerクラスを継承して独自の衝突判定クラスを定義する.(仮にMyContactListenerクラスとする)
    • ContactListener自体は抽象クラスなのでそのままでは使えないので注意
  • MyContactListenerにContactListenerのメソッドのいくつかをオーバーロードする
    • 以下の3つがある
      • Add : 衝突した時に呼び出される
      • Persist : 衝突が維持されている時に呼び出される
      • Remove : 衝突が解除されたときに呼び出される
  • MyContactListenerクラスをWorldクラスに登録する.

といったことをします.
さらに,衝突した瞬間ではなく,あるプロセスで衝突したものについてまとめて処理したい,といった場合は,まずAdd(or Persist)で呼び出された剛体を全部Listに突っ込んで,その上でMyContactListenerにGetCollideListみたいなメソッドを用意して必要な時に呼び出す,といったことをしなければなりません.

関係

まとめると各クラスは以下のような関係になっています.

より詳細な情報

最後に,参考になりそうなサイトを適当に挙げておきます.

Box2D - Home

オフィシャルのサイト.
ダウンロード及び必要な情報はとりあえずここから.

Box2D v2.0.2 User Manual

オフィシャルのマニュアルです.英語.
とりあえず困ったらこれ読めばいいと思います.

Box2Dユーザマニュアル - ずっと君のターン

英語で読むのが辛いマニュアルの一部を和訳した人がいるようで.
バージョンが少し古いためか,一部訳が異なっている部分があるので注意.

[Box2D] 2D物理エンジンを使ったみた (C#ソース付) - fslasht の日記

Box2Dの導入からC#によるBox2Dのサンプルまで載っています.
とりあえずマニュアルを読みつつここのサンプルを眺めればなんとなくわかるんじゃないでしょうか.

Box2DFlashAS3 の単純なサンプルと使い方 - てっく煮ブログ

コードを交えて1から解説しています.
ActionScriptで書かれていますがどの言語でも参考になるはず.