加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Cocos2d-x 3.x物理引擎概述(2)

发布时间:2020-12-14 16:59:46 所属栏目:百科 来源:网络整理
导读:上篇 碰撞 你是否经历过车祸?是否跟什么物体相撞过?就像车一样,物理刚体对象可以互相接触。当它们接触的时候,就发生了碰撞。当碰撞发生时,它可以被完全忽略,也可以引起一系列事件。 碰撞筛选 碰撞筛选允许你启用或者阻止形状之间碰撞的发生。物理引擎


上篇



碰撞

你是否经历过车祸?是否跟什么物体相撞过?就像车一样,物理刚体对象可以互相接触。当它们接触的时候,就发生了碰撞。当碰撞发生时,它可以被完全忽略,也可以引起一系列事件。

碰撞筛选

碰撞筛选允许你启用或者阻止形状之间碰撞的发生。物理引擎支持使用类型、组位掩码来筛选碰撞。

Cocos2d-x中支持32种碰撞类型。对于每个形状都可以指定其所属的类型。还可以指定有哪些类型可以与这个形状进行碰撞。这些是通过掩码来完成的。例如

auto

sprite1 = addSpriteAtPosition(Vec2(s_centre.x - 150,s_centre.y));

sprite1->getPhysicsBody()->setCategoryBitmask(0x02);// 0010

sprite1->getPhysicsBody()->setCollisionBitmask(0x01);// 0001

sprite1

= addSpriteAtPosition(Vec2(s_centre.x - 150,s_centre.y + 100));

sprite1->getPhysicsBody()->setCollisionBitmask(0x01);//

0001

sprite2 = addSpriteAtPosition(Vec2(s_centre.x + 150,s_centre.y),1);

sprite2->getPhysicsBody()->setCategoryBitmask(0x01);// 0001

sprite2->getPhysicsBody()->setCollisionBitmask(0x02);// 0010

sprite3 = addSpriteAtPosition(Vec2(s_centre.x + 150,s_centre.y + 100),2);

sprite3->getPhysicsBody()->setCategoryBitmask(0x03);// 0011

sprite3->getPhysicsBody()->setCollisionBitmask(0x03);// 0011

可以通过检测、类型比较和碰撞掩码,来确定碰撞的发生:

if((shapeA->getCategoryBitmask() & shapeB->getCollisionBitmask()) == 0 || (shapeB->getCategoryBitmask() & shapeA->getCollisionBitmask()) == 0)

{

//

shapes can't collide

ret

= false;

}


碰撞组允许你指定一个综合组的索引。你可以让具有同一组之索引的形状全都一直碰撞(正索引)或者永不碰撞(负索引或零索引)。组指数不同的形状间进行的碰撞,可以根据类型和掩码来进行筛选。换句话说,组筛选比类型筛选的优先级更高。

连接/关节

还记得之前的术语吗?关节是一种把接触点联结在一起的方式。没错,你可以把它类比为自己身体上的关节。每一个关节都有一个从PhysicsJoint对象获得的定义。在两个不同的刚体之间,所有的关节都是联结在一起的。刚体可以是静态的。你可以使用joint->setCollisionEnable(false)来避免相关联的刚体相互碰撞。很多关节的定义需要你提供一些几何数据。很多情况下,关节由锚点来定义。其余的关节定义数据取决于关节的类型。

  • PhysicsJointFixed:固定关节在一个特定的点上,将两个刚体结合在了一起。如果要创建一些以后会断裂的复杂形状,固定关节是非常有用的。

  • PhysicsJointLimit:一种限制关节,它利用了两个刚体间最大距离,就如同两个刚体被绳子连在一起一样。

  • PhysicsJointPin:针式关节可以让两个刚体独立地围绕锚点进行旋转,就如同它们被钉在一起了一样。

  • PhysicsJointDistance:设定两个刚体间的固定距离。

  • PhysicsJointSpring:用弹簧来联结两个物理刚体

  • PhysicsJointGroove:将一个刚体连到线上,另一个连到点上。

  • PhysicsJointRotarySpring:与弹簧关节相似,但是增加了自旋

  • PhysicsJointRotaryLimit:与限制关节相似,但是增加了自旋

  • PhysicsJointRatchet:与套筒扳手的工作类似

  • PhysicsJointGear:使一对刚体的角速度比率保持是一个常数。

  • PhysicsJointMotor:使一对刚体的相对角速度保持是一个常数。

碰撞检测

碰撞(Contacts)是一种由物理引擎创建的用以管理两个形状间碰撞的对象。Contact对象会自动创建,而非由用户创建。这里有几个与之相关联的术语。

  • contact point:contact point是两个形状相接触的那个点。

  • contact normal:contact normal指的是从一个形状指向另一个形状的单位向量。

你可以从一个碰撞中获取PhysicsShape。从中,你可以获取刚体。

boolonContactBegin(PhysicsContact& contact)

bodyA = contact.getShapeA()->getBody();

bodyB = contact.getShapeB()->getBody();

returntrue;

你可以通过使用contact listener来访问碰撞。contact listener支持多种事件:begin,pre-solve,post-solve,以及separate

  • begin:在这一步骤中,两个形状刚刚开始接触。从回调函数中返回true,可以使碰撞正常发生,若返回false,则物理引擎会将碰撞整个忽略掉。如果返回false值,preSolve()postSolve()回调函数会被禁止运行,不过当两个形状停止重叠时,你仍然可以收到一个单独的事件。

  • pre-solve:在这一步骤中,两个形状接触在一起。如果在回调函数中返回false值,则物理引擎会忽略掉此次碰撞;若返回true,碰撞则会正常进行。此外,你可以使用setRestitution()setSurfaceVelocity()函数来忽略碰撞值,这样就可以提供自定义的恢复系数、摩擦系数和表面速度值。

  • post-solve:两个形状相接触,而它们之间的碰撞已被处理。

  • separate:在这一步骤中,两个形状刚刚停止接触。

也可以使用EventListenerPhysicsContactWithBodies,EventListenerPhysicsContactWithShapes,EventListenerPhysicsContactWithGroup来监听你感兴趣的刚体、形状和组的一些事件。除此之外,你还需要设定与物理接触相关的掩码,因为就算你创建了相关的EventListener,碰撞事件还是不会在默认状态下被接收。

例如:


boolinit()

//create

a static PhysicsBody

sprite = addSpriteAtPosition(s_centre,69);">sprite->setTag(10);

sprite->getPhysicsBody()->setContactTestBitmask(0xFFFFFFFF);

sprite->getPhysicsBody()->setDynamic(false);

//adds

contact event listener

contactListener = EventListenerPhysicsContact::create();

contactListener->onContactBegin

= CC_CALLBACK_1(PhysicsDemoCollisionProcessing::onContactBegin,this);

_eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener,69);">schedule(CC_SCHEDULE_SELECTOR(PhysicsDemoCollisionProcessing::tick),

0.3f);

returnfalse;

voidtick(floatdt)

sprite1 = addSpriteAtPosition(Vec2(s_centre.x + cocos2d::random(-300,300),69);">s_centre.y

+ cocos2d::random(-300,300)));

physicsBody = sprite1->getPhysicsBody();

physicsBody->setVelocity(Vec2(cocos2d::random(-500,500),cocos2d::random(-500,500)));

physicsBody->setContactTestBitmask(0xFFFFFFFF);

nodeA = contact.getShapeA()->getBody()->getNode();

nodeB = contact.getShapeB()->getBody()->getNode();

if(nodeA && nodeB)

if(nodeA->getTag() == 10)

nodeB->removeFromParentAndCleanup(true);

elseif (nodeB->getTag() == 10)

nodeA->removeFromParentAndCleanup(true);

//bodies

can collide

}

查询

你有没有过站在一个地方往四周看的经历?你能看到离你近的东西,也能看到离你远的东西。你能判断出它们离你有多远。物理引擎提供类似的空间查询功能。PhysicsWorld对象目前支持的查询包括点查询、射线查询和矩形查询。

点查询

当你碰到什么东西,比如说你的桌子的时候,你可以将此认为是一个点查询的例子。这使你能够检查在一个点周围的一定距离内是否有形状存在。对于鼠标拾取和简单的传感器来说,点查询是非常有用的。你还可以找到在一个形状上离某定点最近的点,或者找到离某个点最近的形状。

射线查询

当你四处看的时候,在你视线内的某些物体肯定会引起你的注意。像这样的时候,你基本上就算是执行了一次射线查询。你不停地扫描,直到有什么有趣的东西让你停下来。你可以使用对某个形状使用射线查询来获取第一个交叉点。例如:

void tick(float dt)

Vec2

d(300 * cosf(_angle),300 * sinf(_angle));

point2 = s_centre + d;

if(_drawNode)

removeChild(_drawNode);

_drawNode

= DrawNode::create();

points[5];

intnum = 0;

func = [&points,&num](PhysicsWorld& world,69);">constPhysicsRayCastInfo& info,void*

data)->bool

if(num < 5)

points[num++]

= info.contact;

};

s_currScene->getPhysicsWorld()->rayCast(func,69);">s_centre,point2,nullptr);

_drawNode->drawSegment(s_centre,69);">point2,1,Color4F::RED);

for(inti = 0; i < num; ++i)

_drawNode->drawDot(points[i],69);">3,Color4F(1.0f,1.0f,1.0f));

addChild(_drawNode);

_angle

+= 1.5f * (float)M_PI

/ 180.0f;

矩形查询

矩形查询提供了一个大致检查区域中存在的形状的一种快捷方式。它非常容易实现:

auto

func = [](PhysicsWorld& world,PhysicsShape& shape,69);">userData)->bool

//Return

true from the callback to continue rect queries

scene->getPhysicsWorld()->queryRect(func,69);">Rect(0,200,200),69);">A few examples of using a Rect query while doing a logo smash:

这里是在制作撞击logo时使用矩形查询的几个例子:

禁用物理引擎

使用内置的物理引擎是个不错的想法。它又稳定又强大。然而,有时候你会想要使用一些其他的物理引擎。这时候你只需要在base/ccConfig.h中把CC_USE_PHYSICS禁用就好了。


上篇

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读