首页 > 代码库 > cocos2d-x中的Box2D物理引擎

cocos2d-x中的Box2D物理引擎

     在Cocos2d-x中集成了2个物理引擎,一个是Chipmunk,一个是Box2D。前者是用C语言编写的,文档和例子相对较少;Box2D是用C++写的,并且有比较完善的文档和资料。所以在需要使用物理引擎的时候,大多数开发者会选择Box2D。Box2D是一款用来模拟刚体在物理世界运动的仿真引擎。通过Box2D物理引擎,世界中的物体就可以按照运动定律进行运动。

注:Box2D下的类都是以b2为前缀的,希望不要与你的命名相冲突

1. 首先我们介绍下需要用到的基本概念。

世界(world) :世界代表了一个遵循物理规律的空间,所有的物体都在世界中运动,世界具有创建销毁刚体,创建销毁关节等功能

刚体(body) :一块十分坚硬的物质,它上面的任何两点之间的距离都是完全不变的。刚体具体划分为静态刚体,动态刚体和棱柱刚体(漂浮刚体)

形状(shape):一块严格依附于刚体(body)的 2D 碰撞几何结构(collision geometry)。形状通过关联附加到刚体上,这样刚体就具备了视觉上的外形。

关节(joint):它是一种用于把两个或多个物体固定到一起的约束。Box2D 支持的关节类型有:旋转,棱柱,距离等等。关节可以支持限制(limits)和马达(motors)

关节限制(joint limit):一个关节限制(joint limit)限定了一个关节的运动范围。例如人类的胳膊肘只能做某一范围角度的运动

关节马达(joint motor):一个关节马达能依照关节的自由度来驱动所连接的物体。例如,你可以使用一个马达来驱动一个肘的旋转

2. 我们现在来简单的使用下Box2D,体验一下模拟的物理世界

(1)首先需要创建世界,创建世界需要两个步骤,首先生成重力向量,然后根据重力向量生成世界

bool HelloWorld::init()

{

    if ( !CCLayer::init() )

    {

        return false;

    }

    // b2Vec2带的两个参数是表示x,y方向的重力大小,正负表示方向

    b2Vec2 gravity(0.0f,-10.0f);

    

    // 创建Box2D的世界

    world = new b2World(gravity);

    

    // 设置刚体休眠(当刚体到达边界的时候,停止对刚体的计算,节约CPU)

    world->SetAllowSleeping(true);

    

    // 使用连续的物理检测

    world->SetContinuousPhysics(true);

    

    // 注册碰撞检测的监听

    world->SetContactListener(this);

    

    // 创建漂浮刚体

    addBird(1, 3.33, b2_kinematicBody);

    

    // 创建静态刚体

    addGrass(5.0, 0.5, b2_staticBody);

    

    // 设置屏幕可以触摸

    setTouchEnabled(true);

    

    // 开辟线程回调模拟

    this->scheduleUpdate();

    

    return true;

}

 

 (2)创建非静态刚体

void HelloWorld::addBird(float x,float y,b2BodyType objectType){    /*****   构建刚体的参数(包括位置,类型)   *****/        // 定义刚体用到的精灵    CCSprite *sprite = CCSprite::create("bird.png");    addChild(sprite);        // 配置刚体的定义(类似隐形,没有肉体的刚体)    b2BodyDef def;    def.position = b2Vec2(x, y); // 设置位置    def.type = objectType; // 配置刚体的类型,分为三类:静态刚体,漂浮刚体,动态刚体    if (objectType == b2_kinematicBody) {        def.linearVelocity = b2Vec2(2, 0); // 两个参数分别代表横向速度和纵向速度    }        // 定义形状(此处为多边形)    b2PolygonShape birdShape;    // 定义边界(世界边界),参数是半宽,半高,因为生成的大小是其传入参数的2倍    birdShape.SetAsBox(sprite->getContentSize().width / RATIO / 2, sprite->getContentSize().height / RATIO / 2);        // 配置刚体的体积(材料(有肉的实体))    b2FixtureDef fixtureDef;    fixtureDef.density = 1; // 密度    fixtureDef.friction = 0.3; // 摩擦因数    fixtureDef.restitution = 0.8f; // 反弹效果    fixtureDef.shape = &birdShape; // 配置刚体的实体        /*****    构建刚体的形体    *****/        // 创建刚体    birdBody = world->CreateBody(&def);        // 将材料加入到刚体里    birdBody->CreateFixture(&fixtureDef);        // 绑定精灵到刚体    birdBody->SetUserData(sprite);}

 (3) 添加静态刚体

void HelloWorld::addGrass(float x,float y,b2BodyType objectType){    /*****   构建刚体的参数(包括位置,类型)   *****/        // 定义刚体用到的精灵    CCSprite *sprite = CCSprite::create("grass.png");    addChild(sprite,1);        // 配置刚体的定义(类似隐形,没有肉体的刚体)    b2BodyDef def;    def.position = b2Vec2(x, y); // 设置位置    def.type = objectType; // 配置刚体的类型,分为三类:静态刚体,漂浮刚体,动态刚体        // 定义形状(此处为多边形)    b2PolygonShape grassShape;    // 定义边界(世界边界),参数是半宽,半高,因为生成的大小是其传入参数的2倍    grassShape.SetAsBox(sprite->getContentSize().width / RATIO / 2 , sprite->getContentSize().height / RATIO / 2);        // 配置刚体的体积(材料(有肉的实体))    b2FixtureDef fixtureDef;    fixtureDef.density = 1;    fixtureDef.friction = 0.3;    fixtureDef.shape = &grassShape; // 配置刚体的实体        /*****    构建刚体的形体    *****/        // 创建刚体    grassBody = world->CreateBody(&def);        // 将材料加入到刚体里    grassBody->CreateFixture(&fixtureDef);        // 绑定精灵到刚体    grassBody->SetUserData(sprite);    }

 (4)驱动模拟世界

// 世界类用于驱动模拟void HelloWorld::update(float a){    float32 timeStep = 1.0f / 60.f;    // Step()函数的第一个参数是时间步数,后面两个参数分别是速度阶段和位置阶段    world->Step(timeStep, 8, 3);        CCSprite *s;        for (b2Body *b = world->GetBodyList(); b; b = b->GetNext()) {        if (b->GetUserData() != NULL) {            s = (CCSprite*)b->GetUserData();
// 漂浮刚体的运动模拟 s->setPosition(ccp(b->GetPosition().x * RATIO, b->GetPosition().y * RATIO)); if (s->getPosition().x < -10 || s->getPosition().x > 490 || s->getPosition().y < -10) { this->removeChild(s); world->DestroyBody(b); } } }}

 (5)设置屏幕可以触摸,实现触摸屏幕添加刚体的效果

void HelloWorld::registerWithTouchDispatcher(void){    CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 1, false);}

 

bool HelloWorld::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent){    CCPoint p = pTouch->getLocation();        addBird(p.x / RATIO, p.y / RATIO, b2_dynamicBody);        return true;}

 (6)让HelloWorld类继承b2ContactListener,重写BeginContact函数,实现刚体的检测碰撞

// 碰撞检测void HelloWorld::BeginContact(b2Contact* contact){    if ((contact->GetFixtureA()->GetBody() == grassBody || contact->GetFixtureB()->GetBody() == grassBody)) {        CCLog("有鸟落在草地上!");    } else {        CCLog("鸟与鸟之间发生碰撞");    }}

效果如图所示:

 

cocos2d-x中的Box2D物理引擎