VertexHelper工具,另一个是Windows系统下使用的PhysicsEditor工具,我们这里就来讲讲PhysicsEditor工具导出的plist文件在Cococs2d-x中的使用方法。
注意:目前最新版本的PhysicsEditor工具的安装目录下面的Demo里面的GB2ShapeCache-x解析类已经不支持Cocos2d-x 2.x版本,但是我们可以在它原来的基础上进行修改,修改后的GB2ShapeCache-x解析类经过测试,对Cocos2d-x 2.x已经全部支持。下面给出修改后的GB2ShapeCache-x解析类文件:
#ifndef GB2ShapeCache_x_h #define GB2ShapeCache_x_h #include "cocos2d.h" #include <map> class BodyDef; class b2Body; NS_CC_BEGIN class GB2ShapeCache { public: static GB2ShapeCache* sharedGB2ShapeCache(void); public: bool init(); void addShapesWithFile(const std::string &plist); void addFixturesToBody(b2Body *body,const std::string &shape); cocos2d::CCPoint anchorPointForShape(const std::string &shape); void reset(); float getPtmRatio() { return ptmRatio; } ~GB2ShapeCache() {} private: std::map<std::string,BodyDef *> shapeObjects; GB2ShapeCache(void) {} float ptmRatio; }; NS_CC_END #endif
#include "GB2ShapeCache-x.h" #include "Box2D/Box2D.h" #include "cocoa/CCNS.h" using namespace cocos2d; class FixtureDef { public: FixtureDef() :next(NULL) { } ~FixtureDef() { delete next; delete fixture.shape; } FixtureDef *next; b2FixtureDef fixture; int callbackData; }; class BodyDef { public: BodyDef() :fixtures(NULL) { } ~BodyDef() { if (fixtures) delete fixtures; } FixtureDef *fixtures; CCPoint anchorPoint; }; static GB2ShapeCache *_sharedGB2ShapeCache = NULL; GB2ShapeCache* GB2ShapeCache::sharedGB2ShapeCache(void) { if (!_sharedGB2ShapeCache) { _sharedGB2ShapeCache = new GB2ShapeCache(); _sharedGB2ShapeCache->init(); } return _sharedGB2ShapeCache; } bool GB2ShapeCache::init() { return true; } void GB2ShapeCache::reset() { std::map<std::string,BodyDef *>::iterator iter; for (iter = shapeObjects.begin(); iter != shapeObjects.end(); ++iter) { delete iter->second; } shapeObjects.clear(); } void GB2ShapeCache::addFixturesToBody(b2Body *body,const std::string &shape) { std::map<std::string,BodyDef *>::iterator pos = shapeObjects.find(shape); assert(pos != shapeObjects.end()); BodyDef *so = (*pos).second; FixtureDef *fix = so->fixtures; while (fix) { body->CreateFixture(&fix->fixture); fix = fix->next; } } cocos2d::CCPoint GB2ShapeCache::anchorPointForShape(const std::string &shape) { std::map<std::string,BodyDef *>::iterator pos = shapeObjects.find(shape); assert(pos != shapeObjects.end()); BodyDef *bd = (*pos).second; return bd->anchorPoint; } typedef CCDictionary ObjectDict; void GB2ShapeCache::addShapesWithFile(const std::string &plist) { string fullName = CCFileUtils::sharedFileUtils()->fullPathForFilename(plist.c_str()); CCDictionary* dict = CCDictionary::createWithContentsOfFile(fullName.c_str()); CCLOG(fullName.c_str()); CCAssert(dict != NULL,"Shape-file not found"); // not triggered - cocos2dx delivers empty dict if non was found CCAssert(dict->count() != 0,"plist file empty or not existing"); CCDictionary* MetadataDict = (CCDictionary*)dict->objectForKey("Metadata"); int format = MetadataDict->valueForKey("format")->intValue(); ptmRatio = MetadataDict->valueForKey("ptm_ratio")->floatValue(); CCAssert(format == 1,"Format not supported"); CCDictionary* bodyDict = (CCDictionary*)dict->objectForKey("bodies"); b2Vec2 vertices[b2_maxPolygonVertices]; CCLOG("bodydict count %d ",bodyDict->count()); CCDictElement* pElement = NULL; CCDICT_FOREACH(bodyDict,pElement) { CCDictionary* bodyData = (CCDictionary*)pElement->getObject(); CCLOG("body key %s -> bodyData count %d",pElement->getStrKey(),bodyData->count()); BodyDef* bodyDef = new BodyDef(); shapeObjects[pElement->getStrKey()] = bodyDef; CCLOG("anchorpoint %s",bodyData->valueForKey("anchorpoint")->getCString()); bodyDef->anchorPoint = CCPointFromString(bodyData->valueForKey("anchorpoint")->getCString()); CCArray* fixtureList = (CCArray*)(bodyData->objectForKey("fixtures")); FixtureDef **nextFixtureDef = &(bodyDef->fixtures); CCObject* pObj = NULL; CCARRAY_FOREACH(fixtureList,pObj) { b2FixtureDef basicData; CCDictionary* fixtureData = (CCDictionary*)pObj; basicData.filter.categoryBits = fixtureData->valueForKey("filter_categoryBits")->intValue(); basicData.filter.maskBits = fixtureData->valueForKey("filter_maskBits")->intValue(); basicData.filter.groupIndex = fixtureData->valueForKey("filter_groupIndex")->intValue(); basicData.friction = fixtureData->valueForKey("friction")->floatValue(); basicData.density = fixtureData->valueForKey("density")->floatValue(); basicData.restitution = fixtureData->valueForKey("restitution")->floatValue(); basicData.isSensor = fixtureData->valueForKey("isSensor")->boolValue(); int cb = fixtureData->valueForKey("userdataCbValue")->intValue(); int callbackData = cb ? cb : 0; std::string fixtureType = fixtureData->valueForKey("fixture_type")->m_sString; if (fixtureType == "POLYGON") { CCArray* polygonsArray = (CCArray*)fixtureData->objectForKey("polygons"); CCObject* pObject; CCARRAY_FOREACH(polygonsArray,pObject) { FixtureDef *fix = new FixtureDef(); fix->fixture = basicData; // copy basic data fix->callbackData = callbackData; b2PolygonShape *polyshape = new b2PolygonShape(); int vindex = 0; CCArray* polygonArray = (CCArray*)pObject; CCObject* pObject; CCAssert(polygonsArray->count(),"polygonsArray = 0!"); CCARRAY_FOREACH(polygonArray,pObject) { CCPoint offset = CCPointFromString(((CCString *)pObject)->getCString()); vertices[vindex].x = (offset.x / ptmRatio); vertices[vindex].y = (offset.y / ptmRatio); vindex++; } polyshape->Set(vertices,vindex); fix->fixture.shape = polyshape; // create a list *nextFixtureDef = fix; nextFixtureDef = &(fix->next); } } else if (fixtureType == "CIRCLE") { FixtureDef *fix = new FixtureDef(); fix->fixture = basicData; // copy basic data fix->callbackData = callbackData; CCDictionary *circleData = (CCDictionary *)fixtureData->objectForKey("circle"); b2CircleShape *circleShape = new b2CircleShape(); circleShape->m_radius = circleData->valueForKey("radius")->floatValue() / ptmRatio; CCPoint p = CCPointFromString(circleData->valueForKey("position")->getCString()); circleShape->m_p = b2Vec2(p.x / ptmRatio,p.y / ptmRatio); fix->fixture.shape = circleShape; // create a list *nextFixtureDef = fix; nextFixtureDef = &(fix->next); } else { CCAssert(0,"Unknown fixtureType"); } } } }
针对PhysicsEditor工具的使用,很简单,可以自己查找资料,这里就不再累述,我们把导出来的plist文件拷贝到Resource目录下就可以了,下面给出使用代码:
#ifndef __HELLO_WORLD_H__ #define __HELLO_WORLD_H__ #include "cocos2d.h" #include "cocos-ext.h" #include "Box2D/Box2D.h" USING_NS_CC; USING_NS_CC_EXT; class HelloWorld : public cocos2d::CCLayer { public: HelloWorld(); virtual ~HelloWorld(); static cocos2d::CCScene* scene(); virtual void onEnter(); virtual void onExit(); virtual bool ccTouchBegan(CCTouch *pTouch,CCEvent *pEvent); virtual void ccTouchEnded(CCTouch *pTouch,CCEvent *pEvent); virtual bool init(); virtual void update(float dt); CREATE_FUNC(HelloWorld); private: b2World* world; private: void addNewSpriteWithCoords(cocos2d::CCPoint p); }; #endif
// // HelloWorldScene.cpp // Demo // // Created by Andreas L枚w on 11.01.12. // Copyright codeandweb.de 2012. All rights reserved. // #include "HelloWorldScene.h" #include "SimpleAudioEngine.h" #include "GB2ShapeCache-x.h" #define PTM_RATIO 30 HelloWorld::HelloWorld() { } HelloWorld::~HelloWorld() { if (world) { delete world; world = NULL; } } bool HelloWorld::init() { if (!CCLayer::init()) { return false; } // 载入物理形状 GB2ShapeCache::sharedGB2ShapeCache()->addShapesWithFile("Box2D.plist"); // 开启多点触控 //this->setTouchEnabled(true); // 开启重力加速器 //this->setAccelerometerEnabled(true); CCSize winSize = CCDirector::sharedDirector()->getWinSize(); // 定义重力方向 b2Vec2 gravity; gravity.Set(0.0f,-10.0f); // 刚体是否睡眠 bool doSleep = true; bool continuous = true; world = new b2World(gravity); world->SetAllowSleeping(doSleep); world->SetContinuousPhysics(continuous); b2BodyDef groundBodyDef; groundBodyDef.position.Set(winSize.width / 2 / PTM_RATIO,winSize.height / 2 / PTM_RATIO); b2Body* groundBody = world->CreateBody(&groundBodyDef); // 定义一个地面盒形状 b2PolygonShape groundBox; groundBox.SetAsBox(winSize.width / 2 / PTM_RATIO,b2Vec2(0,-winSize.height / 2 / PTM_RATIO),0); b2FixtureDef fixtureDef; fixtureDef.shape = &groundBox; fixtureDef.density = 1; //密度 fixtureDef.friction = 0.5f; //摩擦因数 fixtureDef.restitution = 0.4f; //弹性因数 // 底部 groundBody->CreateFixture(&fixtureDef); // 顶部 groundBox.SetAsBox(winSize.width / 2 / PTM_RATIO,winSize.height / 2 / PTM_RATIO),0); groundBody->CreateFixture(&groundBox,0); // 左边 groundBox.SetAsBox(0,winSize.height / 2 / PTM_RATIO,b2Vec2(-winSize.width / 2 / PTM_RATIO,0),0); // 右边 groundBox.SetAsBox(0,b2Vec2(winSize.width / 2 / PTM_RATIO,0); // 设置精灵 CCLabelTTF *label = CCLabelTTF::create("屏幕顶端","Arial",32); this->addChild(label,0); label->setColor(ccc3(0,255)); label->setPosition(CCPointMake(winSize.width / 2,winSize.height - 50)); this->addNewSpriteWithCoords(CCPointMake(winSize.width / 2,winSize.height / 2)); this->scheduleUpdate(); return true; } string names[] = { "BoxA" /*"hotdog","drink","icecream","icecream2","icecream3","hamburger","orange"*/ }; void HelloWorld::addNewSpriteWithCoords(CCPoint p) { string name = names[0];//names[rand() % 7]; CCLOG("name:%s",name.c_str()); CCSprite *sprite = CCSprite::create((name + ".png").c_str()); sprite->setPosition(p); this->addChild(sprite); b2BodyDef bodyDef; bodyDef.type = b2_dynamicBody; bodyDef.position.Set(p.x / PTM_RATIO,p.y / PTM_RATIO); bodyDef.userData = sprite; b2Body *body = world->CreateBody(&bodyDef); // 刚体添加夹具 GB2ShapeCache::sharedGB2ShapeCache()->addFixturesToBody(body,name.c_str()); sprite->setAnchorPoint(GB2ShapeCache::sharedGB2ShapeCache()->anchorPointForShape(name.c_str())); } void HelloWorld::update(float dt) { int velocityIterations = 8; int positionIterations = 3; world->Step(dt,velocityIterations,positionIterations); for (b2Body* b = world->GetBodyList(); b; b = b->GetNext()) { if (b->GetUserData() != NULL) { CCSprite* myActor = (CCSprite*)b->GetUserData(); myActor->setPosition(CCPointMake(b->GetPosition().x * PTM_RATIO,b->GetPosition().y * PTM_RATIO)); myActor->setRotation(-1 * CC_RADIANS_TO_DEGREES(b->GetAngle())); } } } void HelloWorld::onEnter() { CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this,-128,true); CCLayer::onEnter(); } void HelloWorld::onExit() { CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this); CCLayer::onExit(); } bool HelloWorld::ccTouchBegan(CCTouch *pTouch,CCEvent *pEvent) { return true; } void HelloWorld::ccTouchEnded(CCTouch *pTouch,CCEvent *pEvent) { CCPoint pt = pTouch->getLocation(); this->addNewSpriteWithCoords(pt); } //void HelloWorld::ccTouchesBegan(CCSet *pTouches,CCEvent *pEvent) //{ // CCLOG("HelloWorld::ccTouchesBegan"); // CCSetIterator it; // CCTouch *touch; // // for (it = pTouches->begin(); it != pTouches->end(); it++) // { // touch = (CCTouch*)(*it); // // if (!touch) // break; // // CCPoint location = touch->getLocation(); // this->addNewSpriteWithCoords(location); // } //} CCScene* HelloWorld::scene() { CCScene *scene = CCScene::create(); HelloWorld *layer = HelloWorld::create(); scene->addChild(layer); return scene; }