• 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("鸟与鸟之间发生碰撞");
        }
    }
    

    效果如图所示:

  • 相关阅读:
    Go语言基础(四)
    Go语言基础(一)
    Go语言简介和开发环境搭建
    数据分析(四)数据可视化之Matplotlib
    数据分析(三)Pandas
    git简介与基本操作
    drf框架之三大认证之频率类源码分析
    数据分析(二)numpy
    换零钱问题的非递归解法 SICP 1.2.2中的一个问题
    # Java中的代理类
  • 原文地址:https://www.cnblogs.com/alenoscar/p/4025161.html
Copyright © 2020-2023  润新知