Sunday, November 9, 2014

Using Physics in cocos2dx

In my last entry i tried to explain how to setup a world and a body in cocos2dx. This time i will explain how to replace that with the built in physics in cocos2dx, which is based on chipmunk.

You can follow this tutorial in the documentation.

The concepts are bassically the same, we need a body, attach it to a world and to a sprite and then update the sprite to match our physics. The main advantage of using this engine instead of Box2D is that most of that work is taken care of by the cocos2dx.

In create method you will need:


Scene* GameScene::createScene()
{
    // 'scene' is an autorelease object
 auto scene = Scene::createWithPhysics();
 scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
    
    // 'layer' is an autorelease object
    auto layer = GameScreen::create();
    layer->setPhyWorld(scene->getPhysicsWorld());

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}
The main difference is that you are creating the scene with createWithPhysics().

Your .h should look like this:


using namespace cocos2d;
class GameScene : public cocos2d::Layer
{
public:
    // there's no 'id' in cpp, so we recommend returning the class instance pointer
    static Scene* createScene();

    // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
    virtual bool init();
    
    // implement the "static create()" method manually
    CREATE_FUNC(GameScreen);

 void goToPauseScene(Ref *pSender);
 void goToGameOverScene(Ref *pSender);
 void update(float dt);

 void setPhyWorld(PhysicsWorld *world){m_world=world;}

private:
 PhysicsWorld *m_world;
};

Don't forget to add your using namespace, or it may start causing some conflict and won't run.
And to end replacing Box2D, our init method will be:


bool GameScene::init(){
    if ( !Layer::init() )
    {
        return false;
    }
    
    Size visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();

 auto player = Sprite::create("player.png");
 auto body = PhysicsBody::createCircle(player->getContentSize().width / 2);
 player->setPhysicsBody(body);
 player->setPosition(Point(visibleSize.width/2, visibleSize.height/2));

 this->addChild(player);

    return true;
}

And that's it. As you can see, if you compare it with my past entry, we reduced 16 lines of code to 3, making it easier to understand and mantain.
We didn't even need to update our physics in the main loop or have 2 different scales, one for screen and one for world. The API handles all that for us.

This physics engine, as mentioned before, is based on chipmunk, so it does not have support for CCD (Continuous Collision Detection). There are some extra techniques you will have to use when you need to use bullets or something else that needs this.

As a good resource, there is a comunity driven documentation in github that seems to be pretty good. You can check the programmers guide here.

No comments:

Post a Comment