天天看点

重写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

继续阅读