Tutorial - How combine tiled Map with box2d in Cocos2dx 2.2.2


#1

Hi!
I want to share this information.
I hope it’s very helpful xD

If you do not have the application can download from here: http://www.mapeditor.org/

  1. Open Tiled. File->New (view image: tiled_00.png)
  2. Map->New set of patterns. Search the image: Grass_Tiles_NSMBU.png
  3. Add a new layer objects. Write “objetos”. (view image: tiled_01.png)
  4. Define our rectangular objects. (view image: tiled_02.png and tiled_03.png)
  5. Save our projecy with testCocos2dx.tmx.
  6. HelloWorldScene.h:
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"
#include "Box2D/Box2D.h"
#include "GLES-Render.h"

#define PTM_RATIO 32.0

USING_NS_CC;

class HelloWorld : public cocos2d::CCLayer{
private:
	CCTMXTiledMap *tileMap;
    b2World *b2dWorld;
    GLESDebugDraw *b2dDebugDraw;
    CCSprite *ball;
    b2Body *bodyBall;
public:
    // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
    virtual bool init();  
    virtual void draw();
    // there's no 'id' in cpp, so we recommend returning the class instance pointer
    static cocos2d::CCScene* scene();
    
    // a selector callback
    void menuCloseCallback(CCObject* pSender);
    void setupBox2D(bool isDebug);
    void updateBox2D(float dt);
    // implement the "static node()" method manually
    CREATE_FUNC(HelloWorld);
};

#endif // __HELLOWORLD_SCENE_H__
  1. HelloWorldScene.cpp:
#include "HelloWorldScene.h"

USING_NS_CC;

CCScene* HelloWorld::scene()
{
    // 'scene' is an autorelease object
    CCScene *scene = CCScene::create();
    
    // 'layer' is an autorelease object
    HelloWorld *layer = HelloWorld::create();

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

    // return the scene
    return scene;
}

// on "init" you need to initialize your instance
bool HelloWorld::init(){
    //////////////////////////////
    // 1. super init first
    if ( !CCLayer::init() ){
        return false;
    }
    
    CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
    CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();

    /////////////////////////////
    // 2. add a menu item with "X" image, which is clicked to quit the program
    //    you may modify it.

    // add a "close" icon to exit the progress. it's an autorelease object
    CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
                                        "CloseNormal.png",
                                        "CloseSelected.png",
                                        this,
                                        menu_selector(HelloWorld::menuCloseCallback));
    
	pCloseItem->setPosition(ccp(origin.x + visibleSize.width - pCloseItem->getContentSize().width/2 ,
                                origin.y + pCloseItem->getContentSize().height/2));

    // create menu, it's an autorelease object
    CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
    pMenu->setPosition(CCPointZero);
    this->addChild(pMenu, 1);

    /////////////////////////////
    // 3. add your codes below...
    CCSize winSize = CCDirector::sharedDirector()->getWinSize();
    setupBox2D(true);
    ball = CCSprite::create("ball.png");
    ball->setPosition(ccp(winSize.width/2 ,(winSize.height/2)+100));
    addChild(ball);
    //--------------------------------------------
    b2BodyDef ballBodyDef;
    ballBodyDef.type = b2_dynamicBody;
    ballBodyDef.position.Set(ball->getPositionX()/PTM_RATIO, ball->getPositionY()/PTM_RATIO);
    ballBodyDef.userData = ball;
    bodyBall = b2dWorld->CreateBody(&ballBodyDef);

    b2CircleShape circle;
    circle.m_radius = (ball->getContentSize().height/2)/PTM_RATIO;

    b2FixtureDef ballShapeDef;
    ballShapeDef.shape = &circle;
    ballShapeDef.density = 1.0f;
    ballShapeDef.friction = 0.2f;
    ballShapeDef.restitution = 0.8f;
    bodyBall->CreateFixture(&ballShapeDef);

    //--------------------------------------------
    tileMap = CCTMXTiledMap::create("testCocos2dx.tmx");
    addChild(tileMap,-1);

    CCTMXObjectGroup *objectGroup = tileMap->objectGroupNamed("objetos");

	CCArray *objectSuelos = objectGroup->getObjects();
    for(int i=0;i<objectSuelos->count();i++){
		CCDictionary *propSuelo = (CCDictionary *)objectSuelos->objectAtIndex(i);
		const CCString *x = (CCString *)propSuelo->valueForKey("x");
		const CCString *y = (CCString *)propSuelo->valueForKey("y");
		const CCString *w = (CCString *)propSuelo->valueForKey("width");
		const CCString *h = (CCString *)propSuelo->valueForKey("height");

		   // create the body
		   b2BodyDef bodyDef;
		   bodyDef.type = b2_staticBody;

		   bodyDef.position.Set((x->intValue()+(w->intValue()/2.0))/PTM_RATIO,
				   (y->intValue()+(h->intValue()/2.0))/PTM_RATIO);
		   b2Body* staticBody = b2dWorld->CreateBody(&bodyDef);

		   // define the shape
		   b2PolygonShape shape;
		   shape.SetAsBox((w->intValue()/2.0)/PTM_RATIO,
		      (h->intValue()/2.0)/PTM_RATIO);

		   b2FixtureDef myFixtureDef;
		   myFixtureDef.shape = &shape;
		   myFixtureDef.density = 1;


		   staticBody->CreateFixture(&myFixtureDef); //add a fixture to the body
	}

    //--------------------------------------------
    this->schedule(schedule_selector(HelloWorld::updateBox2D));
    return true;
}

void HelloWorld::updateBox2D(float dt){
	b2dWorld->Step(dt, 10, 10);
    for(b2Body *b = b2dWorld->GetBodyList(); b; b=b->GetNext()) {
        if (b->GetUserData() != NULL) {
            CCSprite *ballData = (CCSprite *)b->GetUserData();
            ballData->setPosition(ccp(b->GetPosition().x * PTM_RATIO,
                    b->GetPosition().y * PTM_RATIO));
            ballData->setRotation(-1 * CC_RADIANS_TO_DEGREES(b->GetAngle()));
        }
    }
}

void HelloWorld::setupBox2D(bool isDebug){
	b2Vec2 gravity = b2Vec2(0.0f, -8.0f);
	b2dWorld = new b2World(gravity);
	b2dWorld->SetAllowSleeping(true);
	b2dWorld->SetContinuousPhysics(true);
	b2dDebugDraw = NULL;
	if(isDebug){
		b2dDebugDraw = new GLESDebugDraw(PTM_RATIO);
		b2dWorld->SetDebugDraw(b2dDebugDraw);
		b2dDebugDraw->SetFlags(b2Draw::e_shapeBit | b2Draw::e_jointBit);
	}
}

void HelloWorld::draw(){
	CCLayer::draw();
	if(b2dDebugDraw){
		ccGLEnableVertexAttribs(kCCVertexAttribFlag_Position);
		kmGLPushMatrix();
		b2dWorld->DrawDebugData();
		kmGLPopMatrix();
	}//fin if
}

void HelloWorld::menuCloseCallback(CCObject* pSender){
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
	CCMessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
#else
    CCDirector::sharedDirector()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    exit(0);
#endif
#endif
}
  1. run As. (view image: runAs.png)
  2. Enjoy :slight_smile:


tiled_03.png (99.0 KB)


runAs.png (68.9 KB)


ball.png (7.9 KB)


Grass_Tiles_NSMBU.png (142.7 KB)


tiled_00.png (12.4 KB)


tiled_01.png (23.7 KB)


tiled_02.png (4.2 KB)


#2

@Solidux

Great tutorials, thanks for your sharing.


#3

Thanks a lot!:slight_smile: