SpriteKit 中的物理接触

Physics contacts in SpriteKit

是否可以解释位掩码在这种简单情况下的工作原理:

 A big (blue) ball.    Contact BitMask 0b0001

 A medium (red) ball.  Contact BitMask 0b0010

 A small (white) ball. Contact BitMask 0b0100

它们之间没有碰撞,因为不知何故它们之间的碰撞被关闭了。我假设通过 32 位一直将它们的碰撞掩码设置为 00...但是让我们把它留给另一个问题,我还没有想出如何关闭它们。

将每个球设置为具有唯一的接触位掩码后,如何在它们接触时提供接触信息?

如何知道哪两个球相互接触了?

是否可以只给任何给定联系人中最大的球接收联系信息?


更新:

我不一定追求代码。如果您需要代码来解释什么是什么、它是如何工作的,以及为什么不管做什么,那就去做吧。

但我真正想要的是了解位掩码如何工作以提供允许确定 "who" 参与任何联系的逻辑。

我给每个球大小一个不同的位掩码的原因是我认为这可能有助于确定两个球之间任何给定接触中更大的球。不过,我可能错了。

更新 2:

对进程进展的理解:

据我了解,这些是流程的一部分:

  1. 将 SKView 子类 SKScene 注册为符合物理世界联系通知委托。这么说也是。

  2. 将位掩码设置为每种类型的身体互动类型的类别,希望了解 and/or 在模拟中控制

  3. 使用这些位掩码通过适当地应用它们来阐明每个 object 希望成为联系人 and/or 冲突的一部分的性质(这里有一些神奇的决策)。

  4. 在注册为委托的同一个 SKView 子类中,用执行某些操作的代码覆盖联系人回调

  5. 创建一些魔法代码来确定 who/what 联系了谁。


我理解其中一些,但不了解设置联系位掩码与类别位掩码命名推理的区别,也不了解如何确定谁联系了谁。

在几乎所有的物理引擎中,碰撞层都是由位掩码表示的。同一碰撞层中的所有 object 将相互碰撞。在位掩码中,每一层都由一个位表示。如果位置 0 的位打开,object 将与其他 object 发生冲突,这些 object 在其位掩码中具有相同位置的位。

在检查碰撞时,物理引擎的 broad-phase 例程仅报告那些在碰撞位掩码中至少有一个公共位设置为 1 的对可能发生碰撞。此检查仅通过与 (&) 两个位掩码来完成。仅当上述检查 returns 结果为 non-zero 时,才会将潜在的冲突对报告给 narrow-phase 例程。

例如,如果您想让蓝球与红球和白球同时碰撞,但又想让红球和白球相互碰撞,您可以将位掩码设置为如下所示:

Blue  -> 0b0011
Red   -> 0b0001
White -> 0b0010

在您的示例中,由于 none 个物体在其碰撞位掩码中设置了一个公共位,因此 none 个物体相互碰撞。在上面的示例中,由于红球和白球在其位掩码中没有公共位,因此它们不会发生碰撞。

您可能希望将所有冲突位掩码设置为 -1(这会打开所有位)并通过 XORing 从掩码中删除 bits/categories。上面的示例将由以下伪代码实现:

blueBody.collisionMask = -1;
whiteBody.collisionMask = -1;
redBody.collisionMask = -1;

redBodyCategory   = 0b0001;
whiteBodyCategory = 0b0010;

whiteBody.collisionMask ^= redBodyCategory;
redBody.collisionMask ^= whiteBodyCategory;

我不使用 SpriteKit,但是根据我从 this SO answer 获得的少量信息,contactTestBitmask 设置了联系时引发事件的类别,而 collisionBitmask 设置 body 将实际碰撞的类别。因此,如果您只需要来自涉及 Blue 球 的联系人 的联系信息,您可以将 contactTestBitmask 设置为以下值我上面的例子。

要检查哪些球相互碰撞,您必须检查位掩码值并辨别哪个是哪个。在上面的例子中,可以通过检查是否 body.contactTestBitmask == 0b0011 来识别蓝球,以此类推 body.

附带说明一下,您可能需要考虑使用合适的游戏引擎,例如 Unity,这将使这一切变得更加容易。

首先,您需要定义精灵是什么,这就是 categoryBitMask 的用途。将其视为精灵的二进制名称,每个数字都是唯一的名称。现在可以为您的精灵指定超过 1 个名称,但为了简单起见,我们将其保留为一个。

contactBitMask 告诉精灵它应该寻找什么名字。

因此在物理阶段,引擎将采用给定的精灵,并使用 contactBitMask 中提供的搜索名称查找所有其他物理精灵。

之后,对原始精灵和过滤列表中的精灵进行评估。

在联系人上,调用didBegin(contact:),联系人包含您需要的所有信息,包括2 个联系人主体。然后检查 categoryBitMask 以获取相关精灵的名称,并根据这些名称进行调节。