Box2D物理引擎

一:概述

Cocos2d-x中集成了2个物理引擎:

  1. Chipmunk:C语言编写,文档和资料相对较少;
  2. Box2D:C++编写,有比较完善的文档和资料,开发者一般会选择Box2D。

二:基本概念

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

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

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

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

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

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

    三:简单实现

  • 世界的创建
Size s=Director::getInstance()->getWinSize();

    // 重力参数
    b2Vec2 gravity;
    // 设置水平和垂直方向上的加速度
    gravity.Set(0.0f, -10.0f);
    // 创建世界
    world=new b2World(gravity);
    // 是否允许物体休眠,如果允许休眠,可以提高物理世界的处理效率,只有发生碰撞时才唤醒对象,节省CPU
    world->SetAllowSleeping(true);
    // 是否开启连续碰撞,计算机智能把一段连续的时间分成许多离散的时间点,在对每个时间点之间的行为进行机选,如果时间点分割的不够细致,速度较快的两个物体碰撞时就可能产生穿透,连续碰撞将启用特殊的算法避免该现象。
    world->SetContinuousPhysics(true);

    // 创建物体定义
    b2BodyDef groundBodyDef;
    groundBodyDef.position.Set(0.0f, 0.0f);
    //groundBodyDef.type=b2_staticBody;
    // 通过物体定义创建地面物体
    b2Body *groundBody=world->CreateBody(&groundBodyDef);

    // 定义一个有边的形状(边界)
    b2EdgeShape groundBox;
        // 底部
    groundBox.Set(b2Vec2(0.0f, 0.0f), b2Vec2(s.width/PTM_PATIO, 0.0f));
    groundBody->CreateFixture(&groundBox, 0.0f);// 使用夹具固定形状到物体上

        // 顶部
    groundBox.Set(b2Vec2(0.0f, s.height/PTM_PATIO), b2Vec2(s.width/PTM_PATIO, s.height/PTM_PATIO));
    groundBody->CreateFixture(&groundBox, 0.0f);

        // 左边
    groundBox.Set(b2Vec2(0.0f, 0.0f), b2Vec2(0.0f, s.height/PTM_PATIO));
    groundBody->CreateFixture(&groundBox, 0.0f);

        // 右边
    groundBox.Set(b2Vec2(s.width/PTM_PATIO, 0), b2Vec2(s.width/PTM_PATIO, s.height/PTM_PATIO));
    groundBody->CreateFixture(&groundBox, 0.0f);
  • 静态刚体的创建
auto sprite=Sprite::create("BoxA.png");
    sprite->setPosition(Vec2(p.x, p.y));
    addChild(sprite);

    // 物体定义
    b2BodyDef bodyDef;
    bodyDef.position.Set(p.x/PTM_PATIO, p.y/PTM_PATIO);

    b2Body *body=world->CreateBody(&bodyDef);// 创建物体
    body->SetUserData(sprite);// 将精灵放置到物体的UserData属性中,这样便于我们从物体中获取相关联的物体。

    // 定义两米见方的盒子形状
    b2PolygonShape dynamicBox;
    dynamicBox.SetAsBox(1.0f, 1.0f);


    b2FixtureDef fixtureDef;// 夹具定义
    fixtureDef.shape=&dynamicBox;// 设置夹具形状
    fixtureDef.density=1.0f;// 设置密度
    fixtureDef.friction=0.4f;// 设置摩擦系数
    // 使用夹具固定形状到物体上,这样物体就有了形状
    body->CreateFixture(&fixtureDef);
  • 动态刚体的创建
auto sp=Sprite::create("circle.png");
    sp->setPosition(p);
    addChild(sp);

    // 物体定义
    b2BodyDef bodyDef;
    bodyDef.type=b2_dynamicBody;// 动态刚体
    bodyDef.position.Set(p.x/PTM_PATIO, p.y/PTM_PATIO);

    b2Body *body=world->CreateBody(&bodyDef);// 创建物体
    body->SetUserData(sp);// 将精灵放置到物体的UserData属性中,这样便于我们从物体中获取相关联的物体。

    // 定义两米见方的盒子形状
    b2CircleShape circle;// 创建一个圆形
    circle.m_radius=20.0/PTM_PATIO;// 设置半径

    b2FixtureDef fixtureDef;// 夹具定义
    fixtureDef.shape=&circle;// 设置夹具形状
    fixtureDef.density=1.0f;// 设置密度
    fixtureDef.friction=0.4f;// 设置摩擦系数
    fixtureDef.restitution=0.7f;
    // 使用夹具固定形状到物体上,这样物体就有了形状
    body->CreateFixture(&fixtureDef);
  • 简单关节的创建
// 创建精灵A
    auto spA=Sprite::create("BoxA.png");
    spA->setPosition(p);
    addChild(spA);
    // 动态物体A定义
    b2BodyDef bodyDef;
    bodyDef.type=b2_dynamicBody;
    bodyDef.position.Set(p.x/PTM_PATIO, p.y/PTM_PATIO);
    b2Body *bodyA=world->CreateBody(&bodyDef);
    bodyA->SetUserData(spA);

    // 创建精灵B
    auto spB=Sprite::create("BoxB.png");
    spB->setPosition(p+Vec2(100, -100));
    addChild(spB);
    // 动态物体B定义
    bodyDef.type=b2_dynamicBody;
    Vec2 posB=spB->getPosition();
    bodyDef.position.Set(posB.x/PTM_PATIO, posB.y/PTM_PATIO);
    b2Body *bodyB=world->CreateBody(&bodyDef);
    bodyB->SetUserData(spB);

    // 定义2米见方的盒子形状
    b2PolygonShape dynamicBox;
    dynamicBox.SetAsBox(1.0f, 1.0f);

    // 动态物体夹具定义
    b2FixtureDef fixtureDef;
    fixtureDef.shape=&dynamicBox;// 形状
    fixtureDef.density=1.0f;// 密度
    fixtureDef.friction=0.3f;// 摩擦系数
    fixtureDef.restitution=0.4f;// 弹性

    // 使用夹具固定形状到物体上
    bodyA->CreateFixture(&fixtureDef);
    bodyB->CreateFixture(&fixtureDef);

    // 距离关节定义
    b2DistanceJointDef jointDef;
    //初始化定义 物体1 物体2 物体1的锚点 物体2的锚点(世界坐标)
    jointDef.Initialize(bodyA, bodyB, bodyA->GetWorldCenter(), bodyB->GetWorldCenter());

    jointDef.collideConnected=true;// 允许相连的物体碰撞
    bodyA->GetWorld()->CreateJoint(&jointDef);

*注:
Box2D v2版本中定义了很多关节。这些关节包括:
距离关节:两个物体之间保持固定的距离。每个物体上的点称为锚点。关节定义是b2DistanceJointDef。
旋转关节:允许物体围绕公共点旋转。关节定义是b2RevoluteJointDef。
平移关节:两个物体之间的相对旋转是固定的,它们可以沿着一个坐标轴进行平移。关节定义是b2PrismaticJointDef。
焊接关节:可以把物体固定在相同方向上。关节定义是b2WeldJointDef。
滑轮关节:滑轮关节用于创建理想的滑轮,两个物体位于绳子两端,绳子通过某个固定点(滑轮的位置)将两个物体连接起来。这样当一个物体升起时,另一个物体就会下降。滑轮两端的绳子总长度不变。关节定义是b2PulleyJointDef。
摩擦关节:降低两个物体之间的相对运动。关节定义是b2FrictionJointDef。
齿轮关节:控制其它两个关节(旋转关节或者平移关节),其中一个的运动会影响另一个。关节定义是b2GearJointDef。
鼠标关节:点击物体上任意一个点可以在世界范围内进行拖动。关节定义是b2MouseJointDef。

  • 时间调度
float timeStep=1/60.0;// 时间步

    /*********  一个时间步遍历8次约束  *********/
    int32 velocityIterations=10;// 遍历10次约束
    int32 positionIterations=1;// 一个时间步

    world->Step(timeStep, velocityIterations, positionIterations);

    // 遍历世界中的所有物体
    for (b2Body *b=world->GetBodyList(); b; b=b->GetNext()) {
        if (b->GetUserData() != nullptr) {
            Sprite *sprite=(Sprite *)b->GetUserData();
            sprite->setPosition(Vec2(b->GetPosition().x*PTM_PATIO, b->GetPosition().y*PTM_PATIO));

            sprite->setRotation(-1*CC_RADIANS_TO_DEGREES(b->GetAngle()));// CC_RADIANS_TO_DEGREES 弧度转换为角度
        }
    }

*注:
Box2D 中有一些数学代码构成的积分器(integrator),积分器在离散的时间点上模
拟物理方程,它将与游戏动画循环一同运行。所以我们需要为 Box2D 选取一个时间
步,通常来说游戏物理引擎需要至少 60Hz 的速度,也就是 1/60 的时间步。你可
以使用更大的时间步,但是你必须更加小心地为你的世界调整定义。我们也不喜欢时
间步变化得太大,所以不要把时间步关联到帧频(除非你真的必须这样做)。直截了当
地,这个就是时间步:
float32 timeStep = 1.0f / 60.0f;

 除了积分器之外,Box2D 中还有约束求解器(constraint solver)。约束求
 解器用于解决模拟中的所有约束,一次一个。单个的约束会被完美的求解,然而当我
 们求解一个约束的时候,我们就会稍微耽误另一个。要得到良好的解,我们需要迭代
 所有约束多次。建议的 Box2D 迭代次数是 10 次。
 可以按自己的喜好去调整这个数,但要记得它是速度与质量之间的平衡。更少的
 迭代会增加性能并降低精度,同样地,更多的迭代会减少性能但提高模拟质量。

*

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值