如何设置SceneKit碰撞检测

时间:2014-12-09 05:35:41

标签: swift scenekit

您好我已经仔细阅读了文档,无法弄清楚如何在场景工具包中设置碰撞检测。有人可以举个例子。 请帮助我非常绝望地想出这个。 谢谢!

编辑: 您好,非常感谢,对不起,我忘了提及我的项目很快。没什么大不了的,我可以在很大程度上翻译自己。

我让BitMasks正常工作,因为物体相互碰撞和反弹。但是,我似乎无法使功能工作

func physicsWorld(world: SCNPhysicsWorld, didBeginContact contact: SCNPhysicsContact){
    let contactMask = contact.nodeA.physicsBody!.categoryBitMask | contact.nodeB.physicsBody!.categoryBitMask
    if (contactMask == (CollisionBallCategory | CollisionTerminatorCategory)) {
        println("Collided")
    }
}

the documentation看来我需要以某种方式将场景物理世界委托分配给这个方法。我不知道该怎么做。

1 个答案:

答案 0 :(得分:33)

在SceneKit中进行碰撞检测的主要内容:

  • 它基于位掩码,它们共同组成一个表。
  • 联系代表是您对碰撞做出回应的方式。

使对象发生碰撞

例如,您可以用简单的英语说明一些游戏设计:

  

小行星相互撞击(并制造较小的小行星)。导弹应该相互穿过,但是要毁掉火箭和小行星。火箭队不应该对导弹做任何事情(只是反过来),但如果一个人太靠近另一个或小行星,你就会遇到一个不好的问题而今天你不会去太空。

通过碰撞检测实现这一点的第一步是根据哪些对进行交互来编写该设计。您可以使用表格执行此操作:

         | Missile | Rocket | Asteroid
--------------------------------------
Missile  | No      | Yes    | Yes
Rocket   | No      | Yes    | Yes
Asteroid | No      | No     | Yes

然后,您可以将表格的标题转换为一组类别常量,以便在代码中使用。

typedef NS_OPTIONS(NSUInteger, CollisionCategory) {
    CollisionCategoryMissile    = 1 << 0,
    CollisionCategoryRocket     = 1 << 1,
    CollisionCategoryAsteroid   = 1 << 2,
};

missile.physicsBody.categoryBitMask = CollisionCategoryMissile;
rocket.physicsBody.categoryBitMask = CollisionCategoryRocket;
asteroid.physicsBody.categoryBitMask = CollisionCategoryAsteroid;

对这些常量使用按位OR来创建填充表格的collisionBitMask值。

missile.physicsBody.collisionBitMask =
    CollisionCategoryRocket | CollisionCategoryAsteroid;
rocket.physicsBody.collisionBitMask =
    CollisionCategoryRocket | CollisionCategoryAsteroid;
asteroid.physicsBody.collisionBitMask = CollisionCategoryAsteroid;

这就是让SceneKit为你解决碰撞所需要的一切(也就是说,互相反弹物体)。

应对碰撞

如果您还希望收到有关碰撞的通知(这样您就可以让导弹炸毁,并让您的船进入小行星结束游戏),您需要在场景的物理上设置contact delegate世界并实现一个或多个在发生联系时被调用的contact delegate methods

在您的联系人委托方法(例如physicsWorld:didBeginContact:)中,您需要找出联系人中涉及哪些类别的主体,哪些是哪个,这样您就可以获得代码执行任何操作你的游戏适用于碰撞:

- (void)physicsWorld:(SCNPhysicsWorld *)world didBeginContact:(SCNPhysicsContact *)contact
{
    CollisionCategory contactMask =
        contact.nodeA.physicsBody.categoryBitMask | contact.nodeB.physicsBody.categoryBitMask;

    // first, sort out what kind of collision
    if (contactMask == (CollisionCategoryMissile | CollisionCategoryRocket)) {
        // next, sort out which body is the missile and which is the rocket
        // and do something about it
        if (contact.nodeA.physicsBody.categoryBitMask == CollisionCategoryMissile) {
            [self hitRocket:contact.nodeB withMissile:contact.nodeA];
        } else {
            [self hitRocket:contact.nodeA withMissile:contact.nodeB];
        }
    } else if (contactMask == (CollisionCategoryMissile | CollisionCategoryAsteroid)) {
        // ... and so on ...
    }
}

将此代码放在您的一个类中(可能是视图控制器 - 无论您将游戏逻辑保持在哪里),并使该类声明符合SCNPhysicsContactDelegate协议。

@interface ViewController: UIViewController <SCNPhysicsContactDelegate>

然后将该对象指定给场景的物理世界作为联系人委托:

// in initial setup, where presumably you already have a reference to your scene
scene.physicsWorld.contactDelegate = self

了解更多

SCNPhysicsBody参考文档中有一些关于冲突解决的内容。 Apple有一些使用碰撞检测的示例代码 - 它是WWDC slidesdemo示例应用程序以及vehicle physics演示中的演示自助餐的一部分。

除此之外,SceneKit的碰撞处理模型与SpriteKit几乎完全相同,因此SpriteKit programming guide中的几乎所有内容对于理解SceneKit中的相同内容也很有用。