操作contactTest和collision位掩码以启用/禁用特定的接触和碰撞。
在本例中,我们将使用4个物体,并仅显示位掩码的最后8位以简化。这4个物体是3个带有物理体的SKSpriteNode和一个边界:
let edge = frame.insetBy(dx: 0, dy: 0)
physicsBody = SKPhysicsBody(edgeLoopFrom: edge)
请注意,“边缘”物理体是场景的物理体,而不是节点的物理体。
我们定义了4个独特的类别。
let purpleSquareCategory: UInt32 = 1 << 0 // bitmask is ...00000001
let redCircleCategory: UInt32 = 1 << 1 // bitmask is ...00000010
let blueSquareCategory: UInt32 = 1 << 2 // bitmask is ...00000100
let edgeCategory: UInt32 = 1 << 31 // bitmask is 10000...00000000
每个物理体都被分配到它所属的类别:
purpleSquare.physicsBody?.categoryBitMask = purpleSquareCategory
redCircle.physicsBody?.categoryBitMask = redCircleCategory
blueSquare.physicsBody?.categoryBitMask = blueSquareCategory
physicsBody?.categoryBitMask = edgeCategory
如果一个物体的collisionBitMask中的一个比特被��置为1,那么它将与任何在其categoryBitMask相同位置上有“1”的物体发生碰撞(弹开)。 contactTestBitMask也是如此。
除非您另外指定,否则所有物体都会互相碰撞,并且不会生成任何接触(当任何东西接触其他任何东西时,您的代码将不会收到通知)。
purpleSquare.physicsBody.collisonBitMask = 11111111111111111111111111111111 // 32 '1's.
在每个位置上,每个位都是“1”,因此与任何其他categoryBitMask进行比较时,Sprite Kit将找到一个“1”,因此会发生碰撞。如果您不希望该物体与某个类别发生碰撞,则必须将collisonBitMask中的正确位设置为“0”,并且其contactTestbitMask设置为所有0:
redCircle.physicsBody.contactTestBitMask = 00000000000000000000000000000000 // 32 '0's
与collisionBitMask相同,只是反过来。
可以使用以下方法关闭物体之间的接触或碰撞(保留现有的接触或碰撞):
nodeA.physicsBody?.collisionBitMask &= ~nodeB.category
我们逻辑上使用与运算的方式,将nodeA的碰撞比特掩码与nodeB的分类比特掩码的否定(取反,即~运算符)进行运算,以“关闭”nodeA的比特掩码的位。例如,停止红圆与紫色正方形的碰撞:
redCircle.physicsBody?.collisionBitMask = redCircle.physicsBody?.collisionBitMask & ~purpleSquareCategory
可以简化为:
redCircle.physicsBody?.collisionBitMask &= ~purpleSquareCategory
解释:
redCircle.physicsBody.collisonBitMask = 11111111111111111111111111111111
purpleSquareCategory = 00000000000000000000000000000001
~purpleSquareCategory = 11111111111111111111111111111110
11111111111111111111111111111111 & 11111111111111111111111111111110 = 11111111111111111111111111111110
redCircle.physicsBody.collisonBitMask现在等于11111111111111111111111111111110,红圆不再与类别为....0001(紫色正方形)的物体碰撞。
您可以直接设置collsionsbitMask而不是关闭单个位:
blueSquare.physicsBody?.collisionBitMask = (redCircleCategory | purpleSquareCategory)
i.e. blueSquare.physicsBody?.collisionBitMask = (....00000010 OR ....00000001)
这等同于 blueSquare.physicsBody?.collisionBitMask = ....00000011
蓝色正方形只会与类别为 ..01 或 ..10 的物体发生碰撞
可以在任何时候使用以下代码打开两个物体之间的接触或碰撞(不影响任何现有的接触或碰撞):
redCircle.physicsBody?.contactTestBitMask |= purpleSquareCategory
我们逻辑与redCircle的bitMask和purpleSquare的category bitMask以“打开”redcircle的bitMask中的那个位。这将使redCircel的bitMas中的任何其他位保持不变。
您可以通过以下方式确保每个形状“弹回”屏幕边缘:
// Make sure everything collides with the screen edge
enumerateChildNodes(withName: "//*") { node, _ in
node.physicsBody?.collisionBitMask |= self.edgeCategory //Add edgeCategory to the collision bit mask
}
注意:
碰撞可以是单向的,即物体A可以与物体B碰撞(弹开),而物体B继续进行好像什么都没有发生一样。如果您想让两个对象彼此弹开,它们必须都被告知与另一个物体碰撞:
blueSquare.physicsBody?.collisionBitMask = redCircleCategory
redcircle.physicsBody?.collisionBitMask = blueSquareCategory
然而,联系并不是单向的;如果您想知道物体A何时接触(联系)物体B,则只需在物体A上设置与物体B相关的接触检测即可。您无需为了物体A而在物体B上设置接触检测。
blueSquare.physicsBody?.contactTestBitMask = redCircleCategory
我们不需要
redcircle.physicsBody?.contactTestBitMask= blueSquareCategory
。
Ranged 1 << 1
Undead 1 << 2
Magic 1 << 3
Regenerate 1 << 4
Burning 1 << 5
Frozen 1 << 6
Poison 1 << 7 <- "1<<7" 是什么意思? - GizGazGo