Cocos2dx 3.x Box2dを使用してカメラをフォローさせる

raharu(仮名)(プログラマー)
これがダイバージェンス1%の先の世界か。。。

なんか横スクロールっぽい物を作成したいなと思って前々回位に
Cocos2dx 3.0 物理演算を試してみる
という記事を書いたのですが、Cocos2dx 3.xで追加されたこの方法では

setPhysicsBodyしたNodeにカメラFollowが出来ない
※2014/5/25日現在

致命的じゃないか!詳細は
closed #4150: fix physics position and rotation bug.
と解決策が出そうな出なさそうなというところです。早く直してほしい。。

しかし、Box2d使えば行けるらしいよ?
という情報をTさんから頂き早速やってみました。

まずは準備

【Cocos2d-xで学ぶBox2D超入門第0回】Box2Dを使う準備〜DebugDraw〜
Cocoa部さんの記事でBox2dを使用する為の準備を詳しく書いてくれていました、
DebugDrawを表示出来るところまで作成しましょう。

ボールと床の作成

HelloWorld::init()に以下の記述をします

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
    //画面サイズサイズを取得
    windowSize = Director::getInstance()->getWinSize();

    //メニューボタンを使う
    ball = Sprite::create("CloseSelected.png");
    ball->setPosition(Point(windowSize.width / 2, windowSize.height / 2));
    addChild(ball);

    //ボールの作成
    b2BodyDef player_body_def;
    player_body_def.type = b2_dynamicBody;
    player_body_def.position.Set(ball->getPositionX() / PTM_RATIO, ball->getPositionY() / PTM_RATIO);
    b2Body *body = _world->CreateBody(&player_body_def);

    b2CircleShape circle;
    circle.m_radius = 10.0 / PTM_RATIO;

    b2FixtureDef fixtureDef;
    fixtureDef.shape = &circle;
    fixtureDef.density = 2;
    fixtureDef.restitution = 0;
    fixtureDef.friction = 0.7;
    body->CreateFixture(&fixtureDef);

    //ballをセット
    body->SetUserData(ball);

    //フォローさせる
    this->runAction(Follow::create(ball));


    //床の作成
    b2BodyDef boxBodyDef;
    boxBodyDef.position.Set(windowSize.width / 2 / PTM_RATIO, 10 / PTM_RATIO);
    b2Body *boxBody = _world->CreateBody(&boxBodyDef);

    b2PolygonShape rect;
    rect.SetAsBox(200 / PTM_RATIO, 10 / PTM_RATIO);

    b2FixtureDef boxFixtureDef;
    boxFixtureDef.shape = ▭
    boxFixtureDef.density = 0.4;
    boxFixtureDef.friction = 0.5;
    boxFixtureDef.restitution = 1.0;
    boxBody->CreateFixture(&boxFixtureDef);

HelloWorld::updateに同期する処理を追記します

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void HelloWorld::update(float delta)
{
    _world->Step(delta, 10, 10);


    //物理オブジェクトと位置を同期させる
    for (b2Body* b = _world->GetBodyList(); b; b = b->GetNext())
    {
        if (b->GetUserData() != NULL) {
            auto ball = (Sprite*)b->GetUserData();
            ball->setPosition( Point( b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO) );
            ball->setRotation( -1 * CC_RADIANS_TO_DEGREES(b->GetAngle()) );
        }
    }
}

エミュレートすると床部分とボールが出来ていて、 カメラがバウンドとともに上下するはずです。

次回はTileMapEditorの使い方をやります