17
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【cocos2dx v3.0 beta2】【Box2D】Box2Dを使わずにすんげー簡単に物理演算エンジンの恩恵を得る方法 前編

Posted at

#物理演算エンジンについて
cocos2d-xを使用してゲームを開発していると、
Box2DやChipmunkという言葉をよく耳にするかと思います。

両方共、古典力学的な法則をシュミレーションするゲーム用2D物理演算エンジンです。
記述されている言語に大きな違いがあり、

Box2D = C++
Chipmunk = C言語

となっています。

どちらかと言うとBox2Dの方が日本では人気なのでは無いでしょうか。
よって、まずはBox2Dでの実装例をご紹介します。

その後、Box2Dを使わずにすんげー簡単な方法を説明します。
(長くなってしまったので2つに分割します)

#cocos2d-x 3.0のBox2Dの実装
cocos2d-x 3.0 beta2で実装するとこのようなコードになります。

Box2DScene.h
#import "cocos2d.h"
#import "Box2D/Box2D.h"
#import "cocos-ext.h"

USING_NS_CC;
USING_NS_CC_EXT;


class Box2DScene : public Layer{
private:
    b2World* world;
    
    Box2DScene();
    ~Box2DScene();
    
    static Box2DScene* scene();
    
    void createWorld();
    void createSprite();
    
    virtual bool init();
    virtual void update(float delta);
public:
    static Scene* createScene();
    CREATE_FUNC(Box2DScene);
    
};
Box2DScene.cpp

#import "Box2dScene.h"
#import "GameConfig.h"

Box2DScene::Box2DScene(){}
Box2DScene::~Box2DScene(){}

Scene* Box2DScene::createScene()
{
    // 'scene' is an autorelease object
    auto scene = Scene::create();
    
    // 'layer' is an autorelease object
    auto layer = Box2DScene::create();
    
    // add layer as a child to scene
    scene->addChild(layer);
    
    // return the scene
    return scene;
}

bool Box2DScene::init(){
    
    createWorld();
    createSprite();
    scheduleUpdate();
    
    return true;
}

/**
 * 物理演算の影響を受ける世界全体を生成します。
 */
void Box2DScene::createWorld(){
    // 構造体
    b2Vec2 gravity;
    gravity.Set(0, -10);
    
    world = new b2World(gravity); // 物理演算の全体を管理するワールドを作る
}

/**
 * scheduleUpdate()で呼ばれます。
 * 物理演算の影響で世界の状態は刻一刻と変化するので、その命令を飛ばす。
 * これを行わないと物理演算の影響が行われない。
 */
void Box2DScene::update(float delta){
    // 物理シミュレーションの正確さを決定するパラメータ
    // (まずはこの値にして、ゲームを見ながら調整を行うと良いらしい)
    int velocityIterations = 8;
    int positionIterations = 1;
    
    // worldを更新する
    world->Step(delta, velocityIterations, positionIterations);
}

void Box2DScene::createSprite(){
    Size winSize = Director::getInstance()->getWinSize();
    
    /**
     *
     剛体は次の手順で作成する。剛体とは物理エンジンの影響をうけることが出来る物質のこと
     
      1. 位置・減衰率などで剛体を定義する。
      2. 剛体を作成するためにワールドを使用する。
      3. 図形・摩擦・密度などから装備を定義する。
      4. 剛体から装備を作成する。
     */
    b2Body* body; // 剛体。rigid body。
    b2BodyDef bodyDef; // 剛体の定義
    b2CircleShape shape; // 装備の形状
    b2FixtureDef fixtureDef; // 装備の形状定義
    
    /* 画像の表示(後でも大丈夫だけど、大きさを取るためにここで) */
    PhysicsSprite* physicsSprite = PhysicsSprite::create("peri1.png");
    
    // 1. 位置・減衰率などで剛体を定義する。
    bodyDef.type = b2_dynamicBody;
    bodyDef.position.Set((winSize.width / 2) / PTM_RATIO, (winSize.height) / PTM_RATIO);
    bodyDef.userData = physicsSprite; // 画像をこの剛体に紐付ける
    
    // 2. 剛体を作成するためにワールドを使用する。
    body = world->CreateBody(&bodyDef);
    
    // 3. 図形・摩擦・密度などから装備を定義する。
    shape.m_radius = physicsSprite->getContentSize().width / PTM_RATIO; // 形状の大きさ
    fixtureDef.shape = &shape; // 形状を紐付ける
    fixtureDef.density = 1; // 密度
    fixtureDef.friction = 0.9; // 摩擦
    
    // 4. 剛体から装備を作成する。
    body->CreateFixture(&fixtureDef);
    
    /** PhysicsSpriteに各種情報をセットする */
    this->addChild(physicsSprite);
    physicsSprite->setB2Body(body);
    physicsSprite->setPTMRatio(PTM_RATIO);
    physicsSprite->setPosition(Point(winSize.width / 2, winSize.height / 2));
}

参考書などを読むとPhysicsSpriteを自作することもありますが、
ここでは、extensions/physics-nodes/CCPhysicsSpriteを使用しています。

以上のようなソースになります。実行してみます。

cocoperi1.png

(写真では分かりづらいですが、落ちてます!)
ソースを見れば分かる通り、地上などを実装しておりませんので、このままではどこまでも落ち続けますが、
ちゃんとBox2Dの恩恵を受けて落下することが確認出来ました。

補足

cocos-extのPhysicsSpriteを使用する時、setPositionなどをsetB2Body前に行うと実行時に落ちます。
ソースを見てみると

PhysicsSprite.cpp
void PhysicsSprite::setPosition(const Point &pos)
{
#if CC_ENABLE_CHIPMUNK_INTEGRATION

    cpVect cpPos = cpv(pos.x, pos.y);
    cpBodySetPos(_CPBody, cpPos);

#elif CC_ENABLE_BOX2D_INTEGRATION

    float angle = _pB2Body->GetAngle();
    _pB2Body->SetTransform(b2Vec2(pos.x / _PTMRatio, pos.y / _PTMRatio), angle);
#endif
}

このように_pB2Bodyを利用しているためです。

また、setPTMRatioを設定しないと画像が表示されません。ご注意を。

実行時のパラメータにCC_ENABLE_BOX2D_INTEGRATION=1を加えるのも忘れずに!
(デフォルトではCC_ENABLE_CHIPMUNK_INTEGRATION=1になっているので、Box2Dを利用する場合はこれを消してください。)

後編につづく!

17
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?