Cocos2d-x 3.x物理世界

Box2D 和 Chipmunk2D 是以往 cocos2d 中两款常用的物理引擎,这两个物理引擎精确的说是刚体物理仿真库,这里的物理就是刚体动力学。而我们在谈到这物理引擎的时候,经常会听到刚体(Rigid body)。那什么是刚体?刚体就是在任何外力的作用下,体积和形状都不发生改变的物体。动力学又是什么?动力学是计算刚体在受力作用下随时间移动并相互作用的一个过程。Box2D和Chipmunk2D两个引擎的建构理论基础当然基于此。

  • PhysicsWorld 是 cocos2d 封装的一个用于模拟真实“物理世界”的类。
  • 一个 PhysicsWorld 对象,用于模拟物理碰撞和其他物理行为。你不需要直接创建PhysicsWorld对象;相反,你可以从一个场景对象获取它。

简介

通常,我们通过Scene::create()创建的场景不是基于物理世界的场景。而使用Scene::createWithPhysics()创建场景时,那么这样创建的场景将是基于物理世界的。


PhysicsWorld

  • 设置物理世界的重力值
void setGravity(const Vec2 &gravity);
  • 设置更新物理世界的子步骤的数量。
void setSubsteps(int steps);
  • 设置物理世界的仿真执行速度
void setSpeed(float speed);
  • 获得物理世界的刚体
PhysicsBody * getBody(int tag);
const Vector< PhysicsBody * > & getAllBodies();
  • 移除一个物理刚体
virtual void removeBody(PhysicsBody *body);
virtual void removeBody(int tag);
  • 获得指定坐标上的物理形状
Vector< PhysicsShape * > getShapes (const Vec2 &point);
  • 获得指定坐标上最近的物理形状
PhysicsShape * getShape(const Vec2 &point);
  • 设置物理世界的调试绘制掩码 : 显示物理世界调试状态,显示红色的框,方便调试
void setDebugDrawMask(int mask);
    DEBUGDRAW_NONE :什么都不绘制
    DEBUGDRAW_SHAPE :绘制形状
    DEBUGDRAW_JOINT :绘制关节
    DEBUGDRAW_CONTACT :绘制碰撞
    DEBUGDRAW_ALL : 都绘制
  • 控制物理迭代的方法
void setAutoStep(bool autoStep); 
// 如果设置False的话,那么setSpeed和setSubsteps,以及setUpdateRate函数都不能正常工作了
// 如果为false,那么刚体将停止不动。
  • 物理世界的默认属性
 _gravity(Vec2(0.0f, -98.0f)) : 98cm/s2
, _speed(1.0f)
, _updateRate(1)
, _updateRateCount(0)
, _updateTime(0.0f)
, _substeps(1)
, _cpSpace(nullptr)
, _updateBodyTransform(false)
, _scene(nullptr)
, _autoStep(true)
, _debugDraw(nullptr)
, _debugDrawMask(DEBUGDRAW_NONE)
, _eventDispatcher(nullptr)

创建的物理世界,默认是向下为98个像素每秒的加速度,且对于物理世界中的刚体是默认自动执行物理效果。可以通过setGravity()改变物理世界的重力值,setAutoStep()设置是否对刚体执行物理迭代。

通常使用方法:

// 创建基于物理世界的场景
Scene * scene = Scene::createWithPhysics();
// 设置物理世界的重力值 
scene->getPhysicsWorld()->setGravity(Vec2(0, 10));

//创建一个物理刚体
PhysicsBody * body = PhysicsBody::create();
// 设置刚体的运动速度
body->setVelocity(Vec2(0,500));
// 设置该刚体是否受物理世界的重力值影响
body->setGravityEnable(true);

Sprite * sp = Sprite("xxx.png");
scene->addChild(sp);
// 让精灵对象绑定刚体:该精灵对象受物理世界影响
sp->setPhysicsBody(body);


PhysicsBody

刚体:在任何外力的作用下,体积和形状都不发生改变的物体。

  • 默认属性
: _world(nullptr)
, _cpBody(nullptr)
, _dynamic(true)
, _rotationEnabled(true)
, _gravityEnabled(true) //默认是受物理世界的重力值影响的,且刚体的初始速度是0
, _massDefault(true)
, _momentDefault(true)
, _mass(MASS_DEFAULT)
, _area(0.0f)
, _density(0.0f)
, _moment(MOMENT_DEFAULT)
, _isDamping(false)
, _linearDamping(0.0f)
, _angularDamping(0.0f)
, _tag(0)
, _rotationOffset(0)
, _recordedRotation(0.0f)
, _recordedAngle(0.0)
, _massSetByUser(false)
, _momentSetByUser(false)
, _recordScaleX(1.f)
, _recordScaleY(1.f)
  • 设置刚体的初始速度
void setVelocity(const Vec2 &velocity);
  • 设置刚体的最大速度值
void setVelocityLimit(float limit);
  • 设置刚体的速度
void setAngularVelocity(float velocity);
  • 设置刚体的最大角速度
void setAngularVelocityLimit(float limit);
  • 给刚体施加一个立即起效的冲量
void applyImpulse(const Vect &impulse);
  • 获得刚体所在的物理世界
PhysicsWorld * getWorld();

刚体的掩码

  • CategoryBitmask 类型掩码 : 默认值#ffffffff
    每一个场景中的物理刚体被会分配32个种类,每一个对应一个掩码值。你可以在游戏中自定义掩码值。与collisionBitMask和contactTestBitMask属性结合,你可以定义哪些物理刚体以及什么时候会互相影响。

  • ContactTestBitmask 接触分组掩码 : 默认值0

    • 它决定有哪些物理刚体与它产生接触的时候 回掉函数 会被调用。
    • 当两个刚体在同一个空间中接触时,一个刚体的分组掩码会与另一个的分组掩码做逻辑与操作,如果结果非0,一个PhysicsContact接触对象会被创建并传递給物理世界的代理。为了优化性能,可以只为那些你需要处理接触的刚体之间设置不同的分组掩码。
  • setCollisionBitmask 碰撞分组掩码 : 默认值#ffffffff

    • 设置这个物理刚体的碰撞分组掩码,它决定有哪些物理刚体会与它产生碰撞。
    • 当两个刚体在同一个空间中接触时,一个需要处理的碰撞就有可能产生,一个刚体的分组掩码会与另一个的分组掩码做逻辑与操作,如果结果非0,那么刚体就会受碰撞所影响。刚体分别选择是否对碰撞做出响应并影响自己的运动。打个比方,你可以避免碰撞计算所引起的对刚体速度的微小影响。

例子

1 接触有效
只要接触了就会调用设置的回掉函数。

    /* 物理边界 */
Size sz = Director::getInstance()->getVisibleSize();

    /* 创建 多边形形状 的物理边界 */
Vec2 pos1 = Vec2(-sz.width / 2, 0);
Vec2 pos2 = Vec2(sz.width / 2, sz.height / 2);
Vec2 pos3 = Vec2(sz.width / 2, -sz.height / 2);
Vec2 posVec[3] = { pos1, pos2, pos3 };

PhysicsBody * body = PhysicsBody::createEdgePolygon(posVec, 3); 

body->setCollisionBitmask(3);

    /* 物理世界边界 */
Node * node = Node::create();
node->setPosition(Point(sz.width / 2, sz.height / 2));
node->setPhysicsBody(body);
scene->addChild(node);
    Size sz = Director::getInstance()->getVisibleSize();
    Vec2 center = Vec2(sz.width / 2, sz.height / 2);

    Sprite * sp1 = Sprite::create("CloseNormal.png");
    sp1->setPosition(sz.width / 4, sz.height/2);

    PhysicsBody * body1 = PhysicsBody::createCircle(sp1->getContentSize().width / 2);
    body1->setVelocity(Vec2(0, -98));
    body1->setGravityEnable(true);

    /* 设置刚体的掩码属性 */
    body1->setContactTestBitmask(1);
    sp1->setPhysicsBody(body1);
    this->addChild(sp1);


    Sprite * sp2 = Sprite::create("CloseNormal.png");
    sp2->setPosition(sz.width * 3 / 4, sz.height/2);

    PhysicsBody * body2 = PhysicsBody::createCircle(sp2->getContentSize().width / 2);
    body2->setVelocity(Vec2(0, 90));
    sp2->setPhysicsBody(body2);
    this->addChild(sp2);
    body2->setContactTestBitmask(3); // 因为 1 与 3 不为0,所以body1和body2接触后将触发回掉函数

    /* 两个刚体接触的第一次就触发 */ 
    auto listener = EventListenerPhysicsContactWithBodies::create(body2, body1);
    listener->onContactBegin = [sp1](PhysicsContact& contact){ log("yes...."); sp1->setVisible(false); //接触后,一个球消失 sp1->removeFromParent(); return true; }; Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this);

Cocos2d-x 3.x物理世界_第1张图片

2 碰撞有效
只要碰撞了就会调用回调函数。

    /* 物理边界 */
Size sz = Director::getInstance()->getVisibleSize();

    /* 创建 多边形形状 的物理边界 */
Vec2 pos1 = Vec2(-sz.width / 2, 0);
Vec2 pos2 = Vec2(sz.width / 2, sz.height / 2);
Vec2 pos3 = Vec2(sz.width / 2, -sz.height / 2);
Vec2 posVec[3] = { pos1, pos2, pos3 };

PhysicsBody * body = PhysicsBody::createEdgePolygon(posVec, 3); 

body->setCollisionBitmask(3); //边界的碰撞掩码是3

    /* 物理世界边界 */
Node * node = Node::create();
node->setPosition(Point(sz.width / 2, sz.height / 2));
node->setPhysicsBody(body);
scene->addChild(node);
    Size sz = Director::getInstance()->getVisibleSize();
    Vec2 center = Vec2(sz.width / 2, sz.height / 2);

    Sprite * sp1 = Sprite::create("CloseNormal.png");
    sp1->setPosition(sz.width / 4, sz.height/2);

    PhysicsBody * body1 = PhysicsBody::createCircle(sp1->getContentSize().width / 2);
    body1->setVelocity(Vec2(0, -98));
    body1->setGravityEnable(true);

    /* 设置刚体的掩码属性 */
    body1->setCollisionBitmask(0); // 因为3 与 0 为0,所以body和body1即使碰撞了,也不会调用碰撞回调函数,也不会产生碰撞效果。
    sp1->setPhysicsBody(body1);
    this->addChild(sp1);

Cocos2d-x 3.x物理世界_第2张图片

你可能感兴趣的:(Cocos2d-x 3.x物理世界)