PhysicsEditor 是一个针对2D物理引擎的碰撞外形描点工具。(关于这个描述,听起来比较拗口,具体的可以参考官网)
这个工具是收费的,可支持windows,mac osx。同类的工具免费的有VertexHelper。
可从github上clone,通过xcode build后将product目录下的app文件拖到Application目录安装使用。
github地址:https://github.com/jfahrenkrug/VertexHelper.git
相比较来说PhysicsEditor有几个优点:
1、支持windows平台
2、可到处plist文件,在构建shape的时候减少人肉复制顶点坐标的时间,提升效率;同时保证代码的整洁。
3、官网提供了对cocos2d-x的支持 PyhsicsEditor对cocos2d-x的官方支持
但悲催的是官网的支持使用的是cocos2d-x 1.x版本的,而现在cocos2d-x已更新到2.x了,已有很多接口变动了。
具体可以看cocos2d-x 官网wiki http://www.cocos2d-x.org/projects/cocos2d-x/wiki/Cocos2d-x_v20_migration_guide
针对cocos2d-x 2.x版本的接口改动,对PhysicsEditor的官方支持做了一些修改:
1、将类名前缀修改为CC
2、将1.x版本的CCDictionary,CCMutableArray 的接口调整为 2.x的CCDictionary,CCArray的接口
3、更新CCFileUtils的接口使用
4、调整原来的添加bodyDef到 map中的代码位置调整(减少不必要的循环操作)
下面贴出源码:
// // CCShapeCache.h // #ifndef __CCSHAPECACHE_H__ #define __CCSHAPECACHE_H__ #include "cocos2d.h" USING_NS_CC; class BodyDef; class b2Body; namespace cocos2d { class CCShapeCache : public CCObject{ public: // Static interface static CCShapeCache* sharedShapeCache(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; } ~CCShapeCache() {} private: std::map<std::string, BodyDef *> shapeObjects; CCShapeCache(void) {} float ptmRatio; }; } #endif /* defined(__CCSHAPECACHE_H__) */
// // CCShapeCache.cpp // // #include "CCShapeCache.h" #include "Box2D.h" #include "CCNS.h" 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 CCShapeCache *_sharedShapeCache = NULL; CCShapeCache* CCShapeCache::sharedShapeCache(void) { if (!_sharedShapeCache) { _sharedShapeCache = new CCShapeCache(); _sharedShapeCache->init(); } return _sharedShapeCache; } bool CCShapeCache::init() { return true; } void CCShapeCache::reset() { std::map<std::string, BodyDef *>::iterator iter; for (iter = shapeObjects.begin() ; iter != shapeObjects.end() ; ++iter) { delete iter->second; } shapeObjects.clear(); } void CCShapeCache::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 CCShapeCache::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; } void CCShapeCache::addShapesWithFile(const std::string &plist) { const char* fullName = CCFileUtils::sharedFileUtils()->fullPathFromRelativePath(plist.c_str()); CCDictionary* dict = CCDictionary::createWithContentsOfFile(fullName); 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; assert(polygonsArray->count() <= b2_maxPolygonVertices); CCObject* pPointObject; CCARRAY_FOREACH(polygonArray, pPointObject) { CCString* pointStr = (CCString*)pPointObject; CCPoint offset = CCPointFromString(pointStr->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"); } } } }