热门IT资讯网

LevelHelper Cocos2d-x with Box2d(二)处理碰撞事件

发表于:2024-11-29 作者:热门IT资讯网编辑
编辑最后更新 2024年11月29日,1、在各种不同类型的精灵之间注册碰撞考虑到你的游戏中拥有各种不同类型的精灵,但有时候我们只关心其中某两种类型之间的碰撞。例如在超级玛丽中,马里奥(Mario)和关卡中的硬币、站点(CheckPoint

1、在各种不同类型的精灵之间注册碰撞

考虑到你的游戏中拥有各种不同类型的精灵,但有时候我们只关心其中某两种类型之间的碰撞。

例如在超级玛丽中,马里奥(Mario)和关卡中的硬币、站点(CheckPoint,不知道咋翻译)、乌龟之间的碰撞。在这种情况下,让我们先来定义碰撞的回调函数吧。

你可以同时定义碰撞前后的回调函数,也可以只定义碰撞前,或者碰撞后。具体得按你游戏中需求来做,代码如下

  1. void HelloWorld::preCollisionBetweenMarioAndCoin(LHContactInfo* contact)
  2. {
  3. CCLog("PRE Mario ... Coin");
  4. }
  5. void HelloWorld::preCollisionBetweenMarioAndTurtle(LHContactInfo* contact)
  6. {
  7. CCLog("Mario ... Turtle");
  8. }
  9. void HelloWorld::preCollisionBetweenMarioAndCheckpoint(LHContactInfo* contact)
  10. {
  11. CCLog(@"Mario ... Checkpoint");
  12. }
  13. void HelloWorld::postCollisionBetweenMarioAndCoin(LHContactInfo* contact)
  14. {
  15. CCLog(@"Mario ... Coin");
  16. }
  17. void HelloWorld::postCollisionBetweenMarioAndTurtle(LHContactInfo* contact)
  18. {
  19. CCLog(@"Mario ... Turtle");
  20. }
  21. void HelloWorld::postCollisionBetweenMarioAndCheckpoint(LHContactInfo* contact)
  22. {
  23. CCLog(@"Mario ... Checkpoint");
  24. }

现在定义好了我们所需要的函数,接下来就只要让LevelHelper在碰撞发生的时候去调用它们就行了。首先在我们载入关卡的后面写上以下方法:

  1. //creating the objects
  2. loader->addObjectsToWorld(world, this);
  3. ...
  4. loader->useLevelHelperCollisionHandling();//这个方法是必要的,否则碰撞将不会执行
  5. loader->registerPreColisionCallbackBetweenTagA(COIN, MARIO, this,
  6. callfuncO_selector(HelloWorld::preCollisionBetweenMarioAndCoin))
  7. loader->registerPostColisionCallbackBetweenTagA(COIN, MARIO, this,
  8. callfuncO_selector(HelloWorld::postCollisionBetweenMarioAndCoin))
  9. loader->registerPreColisionCallbackBetweenTagA(CHECKPOINT, MARIO, this,
  10. callfuncO_selector(HelloWorld::preCollisionBetweenMarioAndCheckpoint))
  11. loader->registerPostColisionCallbackBetweenTagA(CHECKPOINT, MARIO, this,
  12. callfuncO_selector(HelloWorld::postCollisionBetweenMarioAndCheckpoint))
  13. loader->registerPreColisionCallbackBetweenTagA(TURTLE, MARIO, this,
  14. callfuncO_selector(HelloWorld::preCollisionBetweenMarioAndTurtle))
  15. loader->registerPostColisionCallbackBetweenTagA(TURTLE, MARIO, this,
  16. callfuncO_selector(HelloWorld::postCollisionBetweenMarioAndTurtle))

在碰撞事件的函数中,会发现有一个参数LHContactInfo* contact,它将返回所有发生碰撞时的信息。

为了获得碰撞的两个物体,可以很简单的通过contact来获得:

  1. void HelloWorld::preCollisionBetweenMarioAndCoin(LHContactInfo* contact)
  2. {
  3. CCLog("Mario ... Coin");
  4. b2Body* coin = contact->bodyA;
  5. b2Body* mario= contact->bodyB;
  6. }

更多可用的信息都在LHContactInfo这个类中,详细可以查看具体的源码。下面我简单描述部分属性:

  1. // 获得 TagA/TagB 属性对应的body
  2. b2Body* bodyA = contact->bodyA;
  3. b2Body* bodyB = contact->bodyB;
  4. // 获得 TagA/TagB 属性对应的精灵对象,
  5. // 如果发生碰撞的是贝塞尔曲线/直线, 则返回NULL, 所以使用之前需要核查是否为空
  6. LHSprite* sprA = contact->spriteA();
  7. LHSprite* sprB = contact->spriteB();
  8. // Box2d contact info, 可以查看源码获得它更多的信息
  9. b2Contact* boxContact = contact->contact;
  10. // old manifold info, 只在pre Collision有效
  11. // 如果发生碰撞的body具有Sensor属性, 则返回NULL,使用之前需检查
  12. const b2Manifold* oldManifold = contact->oldManifold;
  13. // 碰撞发生时的冲量信息, 只在post Collision有效
  14. // 如果发生碰撞的body具有Sensor属性, 则返回NULL,使用之前需检查
  15. const b2ContactImpulse* impulse = contact->impulse;

2、静态物体与静态物体, 或者手动移动静态物体与其他类型的物体发生碰撞

在Box2D中,会将静态物体的质量存储为零,静态物体可以让用户手动移动,它速度为零。另外它不会和其他任意类型的物体相互碰撞。

但有时候我们需要检测到静态物体间的相互碰撞。那该怎么做呢?

想象你有一个台阶(platform静态)通过LevelHelper的路径动画上下来回移动;

想象你需要有一个在台阶与玩家之间碰撞发生时的回调函数。

这时,像刚才那样定义的回调函数是不会执行的。

解决方法:

*复制一份platform, 并在LevelHelper中设置为不可见。

*设置新的这个platform属性为: "Is Sensor", "Dynamic", "Is Bullet", "Fixed Rotation",

*设置新的platform tag 与之前的匹配,

*通过距离关节把这两个platform绑定在一块。

现在两个物体就会同时运动,但在游戏中我们看不到新的这个platform,因为它是不可见的。但它却能帮你检测碰撞。帮你处理其他更多的逻辑信息。

0