【问题标题】:Physics contacts in SpriteKitSpriteKit 中的物理接触
【发布时间】:2016-10-08 06:43:54
【问题描述】:

是否有可能解释位掩码如何在这种简单的情况下工作:

 A big (blue) ball.    Contact BitMask 0b0001

 A medium (red) ball.  Contact BitMask 0b0010

 A small (white) ball. Contact BitMask 0b0100

它们之间没有冲突,因为它们之间以某种方式关闭了冲突。我假设通过将它们的碰撞掩码设置为 00 一直到 32 位......但是让我们把它留给另一个问题,我还没有想出如何关闭它们。

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

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

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


更新:

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

但我真正追求的是了解位掩码如何工作以提供允许确定“谁”参与任何联系的逻辑。

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

更新 2:

了解正在进行的流程:

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

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

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

  3. 使用这些位掩码,通过适当地应用这些位掩码来阐明希望成为接触和/或碰撞一部分的每个对象的性质(这里有一些神奇的决策)。

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

  5. 创建一些魔术代码来确定谁/什么联系了谁。


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

【问题讨论】:

    标签: sprite-kit physics bit-masks skphysicscontact


    【解决方案1】:

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

    在检查碰撞时,物理引擎的广泛阶段例程仅将那些在其碰撞位掩码中至少有一个公共位设置为 1 的对报告为潜在碰撞。此检查只需通过对两个位掩码进行 ANDing (&) 即可完成。仅当上述检查返回非零结果时,才会将潜在的冲突对报告给窄相例程。

    例如,如果您希望蓝球与红球和白球同时碰撞,但希望红球和白球相互碰撞,您可以将位掩码设置为有点如下:

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

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

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

    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 设置了正文的类别实际上会发生碰撞。因此,如果您只需要联系人涉及蓝色的联系信息,您可以将contactTestBitmask 设置为上面示例中的值。

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

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

    【讨论】:

    • “像 Unity 这样合适的游戏引擎”让我发笑。 Unity 没有什么合适的。但谢谢你剩下的。我仍然不确定我明白了。但这是一个非常好的答案。我需要再考虑一下。
    • @Confused 我个人认为 Unity 是目前最好和最模块化的引擎之一,但如果您不喜欢 Unity,还有许多其他选项,例如 Unreal。另请查看我的最新编辑。
    • 我认为我遇到的最大三个问题是 1. 位运算、位关系和位逻辑。
    • Unity 和 Unreal 的大小都是 iOS 开发的问题,而且它们的性能低劣。我承认,虚幻引擎是一个合适的游戏引擎。
    • @Confused 设置唯一的碰撞掩码将无济于事。设置独特的类别位掩码将帮助您做您想做的事。您需要检查类别掩码是否等于每个对象的唯一掩码值。例如,redCategory = 0b0010; if(contactBody.categoryMask == redCategory) { // contactBody is the red ball } 类别位掩码有助于识别正文属于哪个类别。碰撞和接触测试位掩码中的每个位对应一个类别。如果某个位处于打开状态,则该类别的碰撞/接触事件处于打开状态。
    【解决方案2】:

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

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

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

    在此之后,将对原始精灵和过滤列表中的精灵执行评估。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多