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");
}
}
}
}