Showing posts with label Physics. Show all posts
Showing posts with label Physics. Show all posts

Sunday, November 9, 2014

Creating Boundaries for our physics world

In the game i am making, i want my player to be inside a cage or locked room. To achieve this is pretty easy using physics:


auto edgeBody = PhysicsBody::createEdgeBox(visibleSize, PHYSICSBODY_MATERIAL_DEFAULT, METER_TO_PIXEL(1));
auto edgeNode = Node::create();
edgeNode->setPosition(Point(visibleSize.width/2,visibleSize.height/2));
edgeNode->setPhysicsBody(edgeBody);
this->addChild(edgeNode);

We need to create a node because bodies need to be attached to something. We could do the same with a sprite that was going to act as a border or could just leave it like that and put the art on top of it as it is not going to be movable.

I am using a couple macros:

#define PTM_RATIO 32

#define METER_TO_PIXEL(n) ((n) * PTM_RATIO) //macro to convert meters to pixels.

#define PIXEL_TO_METER(n) ((n) / PTM_RATIO) //macro to convert pixels to meters.

PTM_RATIO defines how many pixels i have per meter and the other two allow me to switch between them, so i can basically work in meters in my game.
My PTM_RATIO is 32 and my DesignResolution is 480x320, so i have an area of 15mx10m.

In this example i am creating the edge at the end of the visible size, but i am using a thickness of 1 meter (in every direction), so as a result i have a border around my screen of 1 meter (+1 more meter in the non visible area). I doubt he can escape now :P

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.