Siv3D での 2D 物理演算をサポートする Physics (Box2D)


Siv3D AdventCalendar 2016 の 18 日目の記事です.

概要

Siv3D に付属されている HamFramework の機能の一つに,簡易的な 2D 物理シミュレーションを実装できる「Physics」があります.以下のソースコードで玉を転がす遊びができます.

Main.cpp
# include <Siv3D.hpp>
# include <HamFramework.hpp>

void Main()
{
    CameraBox2D camera(Vec2(0, 10), 17.0);

    PhysicsWorld world;

    auto ground = world.createLineString(Vec2(0, 0), { Vec2(-20, 10), Vec2(-20, 0), Vec2(20, 0), Vec2(20, 10) }, none, none, PhysicsBodyType::Static)
        .addLine({ Vec2(15, 20), Vec2(0, 15) })
        .addLine({ Vec2(-15, 10), Vec2(0, 5) });

    Array<PhysicsBody> bodies;

    while (System::Update())
    {
        world.update();
        camera.update();
        {
            const auto t1 = camera.createTransformer();

            if (Input::MouseL.clicked)
            {
                bodies.push_back(world.createCircle(Mouse::PosF(), 1.0));
            }

            Circle(Mouse::PosF(), 1.0).drawFrame(0.05);

            ground.draw();

            for (const auto& body : bodies)
            {
                body.draw();
            }
        }
        camera.draw();
    }
}

2D ゲーム と物理演算

物理演算を活用した 2D ゲームは多く存在します.例えば,Rovio Entertainment が開発した Angry Birds は,物理演算を用いて鳥の主人公を飛ばし,敵やオブジェクトを破壊するゲームです.また Umea 大学の学生 Emil Ernerfeldt の修士論文で開発された Phun (現 Algodoo) は,お絵かき感覚で物理演算を楽しむことができるゲーム(ツール)であり,インターネット上に多くの作品が公開されています.このような物理演算を活用したゲームを作るためには,自分で物理演算用の計算をするか,Box2D や Chipmunk2D 等の物理演算ライブラリを利用する必要がありますが,どちらもソースコードが長くなる傾向がありました.そこで,2D の物理演算を簡単に楽しめる Physics の基本的な使い方を紹介します.

Box2D と Siv3D

HamFramework の Physics は,Box2D を Siv3D から利用しやすいようにまとめた機能です.Box2D とは オープンソースで開発された C++ の 2D ゲーム用物理演算ライブラリで,円形や多角形の剛体の運動や衝突判定をシミュレーションすることが可能です.(先程紹介した Angry Birds もこの Box2D を用いています.)HamFramework の Physics では Siv3D が C++ で開発されていることや,Box2D のドキュメントが豊富であることから,2D 物理演算に Box2D を採用しました.

基本的な使い方

ワールドの生成と更新

Main.cpp
# include <Siv3D.hpp>
# include <HamFramework.hpp>

void Main()
{
    PhysicsWorld world;

    while (System::Update())
    {
        world.update();        
    }
}

  1. HamFramework.hpp をインクルード
  2. PhysicsWorld クラスのインスタンスを作成
  3. メインループの中で PhysicsWorld::update() を呼ぶ

これにより,物理演算を行うための環境が生成されました.この時点では画面に何も表示されません.今後は,この PhysicsWorld オブジェクトを利用して,運動や衝突判定を行う物体 PhysicsBody の生成を行いきます.

物体の生成と描画

Main.cpp
# include <Siv3D.hpp>
# include <HamFramework.hpp>

void Main()
{
    PhysicsWorld world;

    const auto ground = world.createLine(Vec2(0, 10), Line({ 0, 0 }, {640, 0 }), none, none, PhysicsBodyType::Static);
    const auto ball = world.createCircle(Vec2(320, 300), Circle(100));

    while (System::Update())
    {
        world.update();        

        ground.draw();
        ball.draw();
    }
}

  1. PhysicsWorld::create***()PhysicsBody オブジェクトを生成
  2. メインループの中で PhysicsBody::draw() を呼ぶ

PhysicsWorld::create***() の *** の部分にはRect,Circleなどの Siv3D で用いられる図形の名前が入ります.引数には,

  1. 中央の位置
  2. 図形
  3. 物理定数(指定がない場合は none)
  4. フィルタ(指定がない場合は none)
  5. 静止するか運動するを決める PhysicsBodyType

の順番で指定します.中央の位置はその PhysicsBody の配置を意味します.しかし,このままでは不自然な点いくつかあります.

  1. 重力の方向が上に向かっている
  2. 物体の動きが遅い

これは,Box2D の単位がメートル単位であることや,Y 軸の方向が,上方向を正にしている事が原因で発生した現象です.(つまり上の例では,半径 100 [m] の円が高さ 290 [m] から降っている事になります.)そこで以前紹介した ham::Camera2D 機能を活用し,上記の不自然な点を解決します.
http://qiita.com/hamukun8686/items/95471335b8a0fa1d877f

Camera2D の利用

Main.cpp
# include <Siv3D.hpp>
# include <HamFramework.hpp>

void Main()
{
    PhysicsWorld world;

    const auto ground = world.createLine(Vec2(0, -10), Line({ -20, 0 }, { 20, 0 }), none, none, PhysicsBodyType::Static);
    const auto ball = world.createCircle(Vec2(0, 10), Circle(1));

    CameraBox2D camera(Vec2(0, 0), 20);

    while (System::Update())
    {
        camera.update();
        {
            const auto t1 = camera.createTransformer();

            world.update();

            ground.draw();
            ball.draw();
        }
        camera.draw();
    }
}

  1. Camera2D の派生クラスである CameraBox2D オブジェクトの作成と利用

これにより,Y 軸の正の方向は上方向になりした.また,カメラ位置や拡大率を変更できるようになりました.

今後の機能について

HamFramework の Physics 機能は Box2D の機能全体をカバーするため,今後のアップデートで新しい機能を追加していきます.具体的には,衝突時の処理を記述する方法,物体同士を接続して動かすジョイント機能などです.

まとめ

今回は 2D の物理演算をサポートする Physics の基本的な使い方について解説しました.Physics を用いたゲームが公開されることを期待しています.

明日は @Nicious さんの記事です.よろしくお願いいたします.