欢迎光临Software MyZone,有问题可留言或到站点论坛发帖,争取第一时间帮忙解决 || 站点论坛:火龙论坛 || 淘宝小店:应小心的易淘屋 【欢迎大家提建设性意见】

PhysicsEditor的使用

附件: vs2010工程下载

原文链接:http://blog.csdn.net/zhangxaochen/article/details/8018489

PhysicsEditor 是一款很好的box2d 形状生成工具,通过图形界面,点点鼠标,生成形状的plist文件,然后使用他的api生成fixtures加到需要的body中去。

软件的下载地址:

http://www.codeandweb.com/physicseditor

1. 下载安装之后,在类似目录:

D:\Program Files\PhysicsEditor\Examples\Cocos2d-X\Demo

下有使用例子。不过那是个xcode project,如果像我一样使用windows+visual studio,那么你需要新建一个项目,把类似目录:

D:\Program Files\PhysicsEditor\Examples\Cocos2d-X\Demo\Demo\Classes

下的 HelloWorldScene.cpp + HelloWorldScene.h 两个文件拷出来,替换新建的cocos2d-x 项目【注:不适用于cocos2dx 2.0 以下的版本

2. 在路径:

D:\Program Files\PhysicsEditor\Examples\Cocos2d-X\Demo\Demo\generic-box2d-plist 下面,有另外两个需要的文件:

GB2ShapeCache-x.cpp + GB2ShapeCache-x.h,把他们拷贝到新建的工程的Classes目录下。 如果希望只保留这一份.h 和 .cpp 文件,那么把 对应路径加到项目的附加包含目录,并且把 cpp 文件的引用加到工程即可。

生成运行程序,点击屏幕,不断地在屏幕区域里增加水果。像这样:

==========================================================================================

那么,代码里怎么使用这个 plist 文件呢?

1. 构造函数 HelloWorld() 里面:

 // load physics shapes
 GB2ShapeCache::sharedGB2ShapeCache()->addShapesWithFile("shapedefs.plist");

(好像大家都很喜欢单例模式。。。)

2. 成员函数 void HelloWorld::addNewSpriteWithCoords(CCPoint p) 里面:

void HelloWorld::addNewSpriteWithCoords(CCPoint p)
 {
 string name = names[rand()%7];

CCSprite *sprite = CCSprite::spriteWithFile((name+".png").c_str());
 sprite->setPosition(p);
 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);

// add the fixture definitions to the body

GB2ShapeCache *sc = GB2ShapeCache::sharedGB2ShapeCache();
 sc->addFixturesToBody(body, name.c_str());
 sprite->setAnchorPoint(sc->anchorPointForShape(name.c_str()));
 }

先创建精灵,然后用 b2BodyDef 创建一个 body,这时body其实还没有形状。先前的时候我们给body赋予一个fixture是这样:

b2FixtureDef carShapeDef;
 carShapeDef.shape=&carShape;
 carShapeDef.density=10.f;
 carShapeDef.restitution=0.9f;
 //carShapeDef.isSensor=true;
 _carBody->CreateFixture(&carShapeDef);

先创建一个 b2FixtureDef, 给他的shape域一个形状,然后 xxBody->CreateFixture…

而这次,我们却用了 GB2ShapeCache:

GB2ShapeCache *sc = GB2ShapeCache::sharedGB2ShapeCache();
 sc->addFixturesToBody(body, name.c_str());

注意到示例代码里面还有个 setAnchorPoint  的行为,事实上,box2d 里面是没有 anchorPoint 的概念的,这个 sc->anchorPointForShape(name.c_str()) 是 PhysicsEditor 附加的一个标记,因为如果自己使用physicsEditor,默认情况下,生成的坐标值是以图片左下角作为(0,0)计算的,像这样:

这就相当于 anchorPoint跑到了 (0,0),如果sprite没有相应的重设anchorPoint的话,就会产生碰撞检测跟看到的画面不一致的情况,或者debugDraw也可以直接看到 shape 跟 sprite没有重合:

当然,也可以在physicsEditor 里面就把 “anchorPoint” 拖到中央,这样就不必总是记得设定 sprite的anchorPoint 了。。。
以上部分摘自:http://blog.csdn.net/zhangxaochen/article/details/8018489,下面为个人见解:
不过话是这么说,大家都知道技术的更新时很快的:上面部分针对cocos2d-x2.0.2是不靠谱的现在提供靠谱的做法,firedragonpzy亲测
GB2ShapeCache_x.h头文件

//
//  GB2ShapeCache-x.cpp
//
//  Loads physics sprites created with http://www.PhysicsEditor.de
//  To be used with cocos2d-x
//
//  Generic Shape Cache for box2d
//
//  Created by Thomas Broquist
//
//      http://www.PhysicsEditor.de
//      http://texturepacker.com
//      http://www.code-and-web.de
//
//  All rights reserved.
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
//

#ifndef GB2ShapeCache_x_h
#define GB2ShapeCache_x_h

#include "cocos2d.h"

class BodyDef;
class b2Body;

namespace cocos2d {
	class GB2ShapeCache {
	public:
		// Static interface
		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 shapeObjects;
		GB2ShapeCache(void) {}
		float ptmRatio;
	};
}

#endif

GB2ShapeCache_x.cpp文件:

//
//  GB2ShapeCache-x.cpp
//
//  Loads physics sprites created with http://www.PhysicsEditor.de
//  To be used with cocos2d-x
//
//  Generic Shape Cache for box2d
//
//  Created by Thomas Broquist
//
//      http://www.PhysicsEditor.de
//      http://texturepacker.com
//      http://www.code-and-web.de
//
//  All rights reserved.
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
//

#include "GB2ShapeCache-x.h"
#include "Box2D/Box2D.h"
//#include "CCNS.h"
#include "cocoa/CCNS.h"

using namespace cocos2d;

/**
 * Internal class to hold the fixtures
 */
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::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::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::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) {
	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() 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");
            }
        }
    }
}

这个可是郁闷了我好久,主要是CCDictionary的变化,有关CCDictionary的变化,大家可以参考此文:《Cocos2d-x中的词典类CCDictionary深入分析》