无法理解碰撞位掩码的工作原理

14
我正在尝试在Swift中使用碰撞位掩码和联系测试位掩码,我希望两个对象不会发生碰撞,所以我正在做以下事情:
firstNode.physicsBody?.collisionBitMask = 0b01
secondNode?.collisionBitMask = 0b10

因为SpriteKit对这两个数字执行AND操作,所以结果不应该是00吗,因为10 & 01 = 00

那么为什么还是发生了碰撞呢?

谢谢。

2个回答

11
这不是碰撞处理的方式。当两个物体相交时,物理引擎会在当前物体的collisionBitMask和其他物体的categoryBitMask之间执行逻辑AND运算:
当两个物理体接触时,可能会发生碰撞。通过执行逻辑AND操作将该体的碰撞掩码与另一个体的类别掩码进行比较。如果结果是非零值,则该体受到碰撞的影响。每个实体独立选择是否希望受到其他实体的影响。例如,您可以使用此功能来避免对速度产生微不足道变化的身体进行碰撞计算。 来源
因此,结果取决于您如何设置这两个物体的categoryBitMaskcategoryBitMask的默认值为0xFFFFFFFF,表示所有位都被设置。 因此,当您在0xFFFFFFFF0b100b01之间执行&运算时,结果将是非零值,从而发生碰撞。
例如,像这样设置您的物体:
spriteA.physicsBody?.categoryBitMask = 0b01
spriteA.physicsBody?.collisionBitMask = 0b01

并且

spriteB.physicsBody?.categoryBitMask = 0b10
spriteB.physicsBody?.collisionBitMask = 0b10

这将给你想要的结果。此外,这可能不是你需要的确切设置,这只是一个简单的例子,你需要根据自己的需求更改值。在这种情况下,spriteA仅与具有categoryBitMask设置为0b01的物体发生碰撞。spriteB也是如此,它将与具有categoryBitMask设置为0b10的物体发生碰撞。

另外,如果您不希望这些精灵与任何东西发生碰撞,只需将它们的collisionBitMask属性设置为0即可。


哇,谢谢你提供这么详细的答案!解决了我的问题! - Pop Flamingo

5

这不是测试节点之间碰撞位的正确方法。

  • categoryBitMask 是对象的类别。
  • collisionBitMask 是对象在发生碰撞时要响应的位掩码。
  • contactTestBitMask 用于在指定位掩码发生交集时进行通知。

假设我有以下内容:

struct PC {
    static var player: UInt32 = 0b10 //2
    static var enemy: UInt32 = 0b100 //4
    static var rock: UInt32 = 0b1000 //8
}

player.physicsBody!.categoryBitMask = PC.player
player.physicsBody!.collisionBitMask = PC.enemy | PC.rock
enemy.physicsBody!.categoryBitMask = PC.enemy
enemy.physicsBody!.collisionBitMask = PC.player

因此,当您在didBeginContact函数中检查交互发生的时间时,可以使用位逻辑来检查它们是否发生了交互。

func didBeginContact(contact: SKPhysicsCountact) {
    //1
    let collision: UInt32 = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask

    //2
    if collision == PC.player | PC.enemy {
        //An interaction occured between the player and enemy.
    }
  1. 变量collision使用了按位或操作符,即|。在这种情况下(如果玩家触碰到敌人),它获取了玩家(bodyA)的类别,即2,并获取了敌人(bodyB)的类别,即4。因此,2(0b10)OR 4(0b100)等于6(0b110),并将其分配给collision。

  2. 然后,在if语句中,它检查6的collision是否等于(PC.player | PC.enemy),如果是true,则发生了玩家和敌人之间的交互,因为6 == 6。

您可以使用变量collision来测试任何交互。例如,在我的测试游戏中,我有以下函数测试哪些对象接触过。

func didBeginContact(contact: SKPhysicsContact) {
    let collision: UInt32 = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask

    //Collision between the penguin and land
    if collision == PhysicsCategory.Land | PhysicsCategory.Animal {
        lostLevel()
    } else if collision == PhysicsCategory.Animal | PhysicsCategory.Pillow {
        animalCounter -= 1
        if animalCounter == 0 {
            wonLevel()
        }
    }
}

2
非常感谢您的回答!! - Pop Flamingo
1
这是一个详细的解释。因此,碰撞位掩码用于由系统识别碰撞,并触发didBeginContant函数,在其中可以使用categoryBitMask来隔离发生的碰撞。 - nnrales

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接