很遺憾,看完該案例後無法正常運作,檢查代碼後,判斷PhyObject裡面的Sprite顯示是缺失的,是時候重寫一個了。
1、建立一個基本PhyObject class,描述物體的基本屬性:
enum SHAPE{
Rect,Circle,Polygon
};
class PhyObject{
public:
bool _isStatic;
float _density;
float _friction;
float _restitution;
float* _shapeData;
SHAPE _shape;
Sprite* _sprite;
b2Body* _body;
void fresh();
};
Cpp檔案裡,描述一個重要的方法,sprite随着實體模型的移動而移動:
void PhyObject::fresh(){
//CCLog("fresh");
Size visibleSize = Director::getInstance()->getVisibleSize();
Point origin = Director::getInstance()->getVisibleOrigin();
b2Vec2 position=this->_body->GetPosition();
float angle=this->_body->GetAngle();
this->_sprite->setPosition
(
Point
(
position.x,
position.y
)
);
this->_sprite->setRotation(-angle*180.0/3.1415926);
}
2、建立一個基本的矩形實體類:
RectPhyObject* RectPhyObject::create(bool isStatic,float* mShapeData,Layer* layer,b2World* world,float density,float friction,float restitution,std::string pic){
RectPhyObject* rectObject=new RectPhyObject;
b2BodyDef bodyDef;
if(!isStatic)
{
bodyDef.type = b2_dynamicBody;
}
bodyDef.position.Set(mShapeData[0], mShapeData[1]);
rectObject->_body = world->CreateBody(&bodyDef);
//body->SetUserData(id);
b2PolygonShape dynamicBox;
dynamicBox.SetAsBox(mShapeData[2], mShapeData[3]);
if(!isStatic)
{
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicBox;
fixtureDef.density = density;
fixtureDef.friction = friction;
fixtureDef.restitution=restitution;
rectObject->_body->CreateFixture(&fixtureDef);
}
else
{
rectObject->_body->CreateFixture(&dynamicBox, 0.0f);
}
rectObject->_sprite = Sprite::create(pic);
layer->addChild(rectObject->_sprite, 1);
Size size=rectObject->_sprite->getContentSize();
float pw=mShapeData[2]*2;
float ph=mShapeData[3]*2;
float scaleX=pw/size.width;
float scaleY=ph/size.height;
rectObject->_sprite->setScaleX(scaleX);
rectObject->_sprite->setScaleY(scaleY);
rectObject->_sprite->setPosition(mShapeData[0],mShapeData[1]);
return rectObject;
}
以上可以根據該物體是否是靜态,決定密度、摩擦、回複系數的值,邊框也是用這個類來生成的。
3、用于碰撞的圓形實體類:
CirclePhyObject* CirclePhyObject::create(bool isStatic,float* mShapeData,Layer* layer,b2World* world,float density,float friction,float restitution,std::string pic){
b2CircleShape dynamicCircle;
dynamicCircle.m_radius=mShapeData[2];
//dynamicBox.SetAsBox(mShapeData[2], mShapeData[3]);
if(!isStatic)
{
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicCircle;
隻有shape會不同,隻要設定半徑就好。
4、看下主遊戲界面:
static int* NUMS=new int[9]{1,2,3,4,5,4,3,2,1};
static std::string SA[8]={
"pic/brownCube.png","pic/pinkCube.png",
"pic/redCube.png","pic/yellowCube.png",
"pic/greenCube.png","pic/blueCube.png",
"pic/violetCube.png","pic/orangeCube.png"
};
被碰撞的物體序列和圖檔來源;
bool HelloWorld::init()
{
if ( !Layer::init() )
{
return false;
}
schedule(schedule_selector(HelloWorld::update), 0.001f);
Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
LayerColor *background = LayerColor::create( Color4B(255,255,255,255) );
this->addChild(background,-20);
b2Vec2 gravity(0.0f, -10.0f);
world = new b2World(gravity);
world->SetAllowSleeping(true);
setGround();
createPyramid();
createBullet();
return true;
}
分别建立架構、被碰撞的物體系列、用于碰撞的物體;記得要注冊幀時間方法(該方法内要調用物體的fresh方法);
void HelloWorld::setGround(){
Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
auto data1=new float[4]{20,450,10,400};
auto object1=RectPhyObject::create(true,data1,this,world, 0, 0, 0, "pic/bolckGrayCube.png");
index=0;
indexStr=new std::string(StringUtils::format("%d", index));
pom[*indexStr]=object1;
auto data2=new float[4]{visibleSize.width-20,450,10,400};
auto object2=RectPhyObject::create(true,data2,this,world, 0, 0, 0, "pic/bolckGrayCube.png");
index++;
indexStr=new std::string(StringUtils::format("%d", index));
pom[*indexStr]=object2;
auto data3=new float[4]{visibleSize.width/2,50,visibleSize.width/2-10,10};
auto object3=RectPhyObject::create(true,data3,this,world, 0, 0, 0, "pic/bolckGrayCube.png");
index++;
indexStr=new std::string(StringUtils::format("%d", index));
pom[*indexStr]=object3;
CCLog("_MAP length is: %d",pom.size());
}
pom是存儲所有物體的map集合;架構裡都是靜态物體;
void HelloWorld::createPyramid(){
for(int i=0;i<9;i++)
{
for(int j=0;j<NUMS[i];j++){
float x=80+i*60;
float y=100+j*60;
auto data=new float[4]{x,y,10,30};
index++;
indexStr=new std::string(StringUtils::format("%d", index));
auto object=RectPhyObject::create(false,data,this,world, 0.6f, 0.1f, 0.2f, SA[index%8]);
pom[*indexStr]=object;
CCLog("set i: %d, j: %d,index: %d",i,j,index);
}
}
}
建立物體系列,分成9排,每排數量由數組MUNS決定,建立的都是動态物體.
void HelloWorld::createBullet(){
auto data=new float[4]{250,800,20,20};
index++;
indexStr=new std::string(StringUtils::format("%d", index));
auto object=CirclePhyObject::create(false,data,this,world, 2.6f, 0.1f, 0.2f, "pic/ball.png");
pom[*indexStr]=object;
CCLog("set index: %d",index);
}
建立掉下來的球形物體;
void HelloWorld::update(float dt){
//CCLOG("update");
step();
std::map<std::string,PhyObject*>::iterator iter;
for(iter=pom.begin();iter!=pom.end();iter++)
{
PhyObject* po=iter->second;
po->fresh();
}
}
好了,加入幀時間動作,物體就都動起來了!
最後小結下,原書裡因該是遺漏了sprite的位置資訊,供大家參考。
源碼:https://github.com/frank1982/Box2DDemo