Cocos2d-x_Box2D刚体使用PhysicsEditor工具生成形状

众所周知,Box2D中的刚体形状如果比较简单,我们可以使用Box2D中的几个形状子类生成,但是如果我们游戏中的刚体的形状比较复杂,那我们需要使用第三方工具生成,而现在Box2D的第三方工具很少,目前所知道的只有两个:一个是在Mac系统下使用的


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, 0, 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, 0, b2Vec2(0, 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);
	groundBody->CreateFixture(&groundBox, 0);

	// 右边
	groundBox.SetAsBox(0, winSize.height / 2 / PTM_RATIO, b2Vec2(winSize.width / 2 / PTM_RATIO, 0), 0);
	groundBody->CreateFixture(&groundBox, 0);

	// 设置精灵
	CCLabelTTF *label = CCLabelTTF::create("屏幕顶端", "Arial", 32);
	this->addChild(label, 0);
	label->setColor(ccc3(0, 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;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值