我正在测试SpriteKit的功能,我遇到了一个问题.我正在阅读比特面具,碰撞,类别和联系.我得到它们是什么,大多数情况下,至少,我没有得到类别位掩码的点,但我得到碰撞位掩码,这是我需要解决我的问题.
好吧我的问题是我有两种不同类型的精灵:对象和第二种.名称并没有多大意义,但它只是为了测试.我希望第二个有冲动,我希望对象有力量.我能够在精灵上应用相应的向量,但我不希望它们相互碰撞.我希望他们通过并忽略彼此的存在.
我尝试通过为彼此分配不同的碰撞位掩码来解决该问题:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let texture = SKTexture(imageNamed: "pokeball")
let object = SKSpriteNode(texture: texture)
object.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: object.size.width,height: object.size.height))
object.physicsBody?.affectedByGravity = false
object.yScale = 0.5
object.xScale = 0.5
for t in touches {
object.position = t.location(in: self)
}
self.addChild(object)
object.physicsBody?.collisionBitMask = UInt32(4)
object.physicsBody?.applyForce(CGVector(dx: 0, dy: 10))
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let texture = SKTexture(imageNamed: "purple")
let second = SKSpriteNode(texture: texture)
let impulse : Double = 20
let x = (impulse * Double(cosf(45)))
let y = Double(impulse * Double(sinf(45)))
let vector = CGVector(dx: x, dy: y)
second.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: second.size.width,height: second.size.height))
second.yScale = 1.5
second.xScale = 1.5
second.physicsBody?.isDynamic = true
for t in touches {
second.position = t.location(in: self)
}
self.addChild(second)
second.physicsBody?.collisionBitMask = UInt32(1)
second.physicsBody?.applyImpulse(vector)
}
Run Code Online (Sandbox Code Playgroud)
所以对象的位掩码为4:
object.physicsBody?.collisionBitMask = UInt32(4)
Run Code Online (Sandbox Code Playgroud)
第二个位掩码为1:
second.physicsBody?.collisionBitMask = UInt32(1)
Run Code Online (Sandbox Code Playgroud)
我跑了模拟器,他们仍然相互碰撞,所以我上网并试图找到一些答案:我发现一个说我必须使用如下数字:
这些是位掩码,你不能使用任意数字1,2,3,4,5 - 你必须使用1,2,4,8,16等 -
有人可以解释原因吗?但是,这不是问题,因为我使用的是1和4
我遇到的下一个问题说我必须使用二进制数字(0100)和(0010),我试过它们,同样的问题:仍然发生冲突.
我将留下碰撞的图片: 碰撞
有谁知道为什么会这样?如果这是一个非常愚蠢的错误或已经被问到的事情,我提前道歉,我就是找不到它.
关于这些主题有很多文档,但这是一个实际的例子.
假装你有三个节点的集合pool,basketball和bowlingball.现在,显然,我们希望basketball并且bowlingball相互碰撞.所以你像这样设置collisionBitMasks:
basketball.physicsBody?.collisionBitMask = UInt32(2)
bowlingball.physicsBody?.collisionBitMask = UInt32(2)
Run Code Online (Sandbox Code Playgroud)
大.现在,我们希望bowlingball沉到底部pool,并basketball与之碰撞pool(可能更多的是飞溅,但忍受我).我们怎么做?我们可以尝试:
pool.physicsBody?.collisionBitMask = UInt32(2) // ?
Run Code Online (Sandbox Code Playgroud)
但是等等,这会使basketballAND bowlingball与之相撞pool.我们只希望basketball与池碰撞,而我们希望bowlingball忽略pool并直接沉到底部而没有碰撞.这是categoryBitMasks派上用场的地方:
let basketballBitMask = UInt32(1)
let bowlingballBitMask = UInt32(2)
let poolBitMask = UInt32(4) // Why 4? See next section
basketball.physicsBody?.categoryBitMask = basketballBitMask
bowlingball.physicsBody?.categoryBitMask = bowlingballBitMask
pool.physicsBody?.categoryBitMask = poolBitMask
Run Code Online (Sandbox Code Playgroud)
由于每个对象都分配有唯一编号,因此您现在可以选择要与另一个对象碰撞的对象:
// basketball physics body collides with bowlingball(2) OR pool(4)
basketball.physicsBody?.collisionBitMask = bowlingballBitMask | poolBitMask
// ( '|' = logical OR operator)
// bowlingball physics body only collides with basketball(1)
bowlingball.physicsBody?.collisionBitMask = basketballBitMask
// pool physics body only collides with basketball(1)
pool.physicsBody?.collisionBitMask = basketballBitmask
Run Code Online (Sandbox Code Playgroud)
如果你不确定是什么奇怪的'|' 符号正在做,我强烈推荐高级操作员的快速文档,以帮助您了解这里发生的事情.
好的,所以我们设置了一些位掩码.但他们是如何使用的呢?如果我们只有两个对象,为什么我们不能只比较collisionBitMasks?
简单地说,这不是它的工作原理.当bowlingball接触到接触pool时,SpriteKit物理学引擎将AND("&")一起bowlingball的categoryBitMask与pool的collisionBitMask(或反之亦然;其结果是一样的):
objectsShouldCollide = (bowlingball.physicsBody?.categoryBitMask &
pool.physicsBody?.collisionBitMask)
// objectsShouldCollide = (ob010 & 0b100) = 0b000
Run Code Online (Sandbox Code Playgroud)
因为bowlingball's categoryBitMask和pool's collisionBitMask共有零位,objectsShouldCollide等于零,SpriteKit会阻止对象发生碰撞.
但是,在你的情况下,你没有设置你的对象categoryBitMask.因此它们的默认值为2 ^ 32,或0xFFFFFFFF(十六进制表示)或二进制,0b11111111111111111111111111111111.因此当"对象"命中"第二个"对象时,SpriteKit会这样做:
objectsShouldCollide = (0b11111111111111111111111111111111 & // Default categoryBitMask for "object"
0b00000000000000000000000000000001) // collisionBitMask for "second" object
// = 0b00000000000000000000000000000001
Run Code Online (Sandbox Code Playgroud)
因此,当你没有定义了objectcategoryBitMask时,无论你设置什么作为second对象collisionBitMask,objectsShouldCollide永远不会为零,它们将永远碰撞.
注意:您可以将对象设置collisionBitMask为0; 但是那个物体永远无法与任何东西发生碰撞.
现在让我们说我们想要包含bowlingball相互碰撞的多个s.简单:
bowlingball.physicsBody?.collisionBitMask = basketballBitMask | bowlingballBitMask
// bowlingball collision bit mask (in binary) = 0b10 | 0b01 = 0b11
// bowlingball collision bit mask (in decimal) = 2 | 1 = 3
Run Code Online (Sandbox Code Playgroud)
在这里你可以看到,如果我们将pools physicsCategory 设置为UInt32(3),它就不再可以与a bowlingball或basketball.
学习有目的地命名变量,即使你只是用它们进行测试(虽然,巧合的是," object和second对象"工作得很好).
使用位掩码结构来简化代码并提高可读性:
struct PhysicsCategory {
static let Obj1 : UInt32 = 0b1 << 0
static let Obj2 : UInt32 = 0b1 << 1
static let Obj3 : UInt32 = 0b1 << 2
static let Obj4 : UInt32 = 0b1 << 3
}
obj1.physicsBody?.categoryBitmask = PhysicsCategory.Obj1 // etc
Run Code Online (Sandbox Code Playgroud)