天天看點

重寫Cocos2d-x 3.0遊戲開發實戰詳解的Box2D案例

很遺憾,看完該案例後無法正常運作,檢查代碼後,判斷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

繼續閱讀