Swift 使用SpriteKit停止对象碰撞
我正在测试SpriteKit的功能,遇到了一个问题。我在读《比特面具》、《碰撞》、《分类》和《接触》。我知道它们是什么,至少大部分情况下,我不明白分类位掩码的意义,但我得到了冲突位掩码,这是我需要解决我的问题 我的问题是我有两种不同类型的精灵:对象和第二种。这些名字没有多大意义,但只是为了测试。我希望第二个物体有一个冲动,我希望物体有一个力。我能够在精灵上应用各自的向量,但我不希望它们相互碰撞。我想让他们直接通过,忽略彼此的存在 我试图通过相互分配不同的冲突位掩码来解决该问题:Swift 使用SpriteKit停止对象碰撞,swift,sprite-kit,Swift,Sprite Kit,我正在测试SpriteKit的功能,遇到了一个问题。我在读《比特面具》、《碰撞》、《分类》和《接触》。我知道它们是什么,至少大部分情况下,我不明白分类位掩码的意义,但我得到了冲突位掩码,这是我需要解决我的问题 我的问题是我有两种不同类型的精灵:对象和第二种。这些名字没有多大意义,但只是为了测试。我希望第二个物体有一个冲动,我希望物体有一个力。我能够在精灵上应用各自的向量,但我不希望它们相互碰撞。我想让他们直接通过,忽略彼此的存在 我试图通过相互分配不同的冲突位掩码来解决该问题: override
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)
}
第二个的位掩码为1:
second.physicsBody?.collisionBitMask = UInt32(1)
我运行了模拟器,但它们仍在相互碰撞,所以我上网试图寻找一些答案:我找到了一个答案,上面说我必须使用如下数字:
这些是位掩码,不能使用任意数字1、2、3、4、5-必须使用1、2、4、8、16等等-
有人能解释一下原因吗?然而,这不是问题所在,因为我使用的是1和4
我遇到的下一个问题是我必须使用二进制数(0100)和(0010),我尝试了它们,同样的问题:仍然冲突
我将留下碰撞的照片:
有人知道为什么会这样吗?如果这是一个非常愚蠢的错误或已经被问到的问题,我会提前道歉。我就是找不到它。有很多关于这些主题的文档,但这里有一个实际的例子 分类的力量 假设您有一个由三个节点组成的集合
pool
、basketball
和bowlingball
。现在,很明显,我们希望篮球和保龄球互相碰撞。因此,您可以这样设置碰撞位掩码:
basketball.physicsBody?.collisionBitMask = UInt32(2)
bowlingball.physicsBody?.collisionBitMask = UInt32(2)
太好了。现在,我们希望保龄球
沉入池底
,篮球
与池
相撞(可能更像是水花,但请耐心等待)。我们怎么做?我们可以尝试:
pool.physicsBody?.collisionBitMask = UInt32(2) // ?
但是等等,那会使篮球和保龄球与游泳池发生碰撞。我们只希望篮球
与游泳池发生碰撞,而保龄球
忽略游泳池
并直接沉入池底而不发生碰撞。这就是categoryBitMask
s派上用场的地方:
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
因为每个对象都有一个指定给它的唯一编号,所以现在可以拾取并选择希望另一个对象与之碰撞的对象:
// 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
如果您不确定奇怪的“|”符号在做什么,我强烈建议使用高级运算符来帮助您了解这里发生了什么
为什么不直接使用冲突位掩码呢?
好的,我们设置了一些小面具。但是它们是如何使用的呢?如果我们只有两个对象,为什么我们不能比较collisionBitMasks呢
简单地说,这不是它的工作原理。当保龄球
与池
接触时,SpriteKit物理引擎会将保龄球
的类别比特掩码与池
的碰撞比特掩码(反之亦然;结果相同):
由于bowlingball
的categoryBitMask
和pool
的collisionBitMask
共有零位,objectsshouldclide
等于零,SpriteKit将阻止对象碰撞
但是,在您的情况下,您没有设置对象的categoryBitMask
s。因此,它们的默认值为2^32,或0xFFFFFF(),或二进制值为0B11111111111111。因此,当“对象”撞击“第二个”对象时,SpriteKit会执行以下操作:
objectsShouldCollide = (0b11111111111111111111111111111111 & // Default categoryBitMask for "object"
0b00000000000000000000000000000001) // collisionBitMask for "second" object
// = 0b00000000000000000000000000000001
因此,当您尚未定义对象的categoryBitMask时,无论您将什么设置为第二个对象的碰撞位掩码
,objectsShouldCollide将永远不会为零,并且始终会发生碰撞
注意:您可以将对象的冲突位掩码设置为0;但是那样的话,这个物体就永远无法与任何物体碰撞
对CategoryBitMask使用2的幂(0,1,2,4,8等)
现在让我们假设我们想要包含多个相互碰撞的保龄球。简单:
bowlingball.physicsBody?.collisionBitMask = basketballBitMask | bowlingballBitMask
// bowlingball collision bit mask (in binary) = 0b10 | 0b01 = 0b11
// bowlingball collision bit mask (in decimal) = 2 | 1 = 3
在这里您可以看到,如果我们将pool
s physicacscategory设置为UInt32(3),它将不再与bowlingball
或basketball
区分开来
进一步建议
学会有目的地使用变量,即使您只是在使用它们进行测试(尽管巧合的是,“object
和second
object”工作得很好)
使用位掩码结构简化代码并提高可读性:
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
结构物理分类{
静态let Obj1:UInt32=0b1为什么不下载并使用这个简单的精灵工具包项目呢?它创建各种几何形状,将其中一些设置为碰撞,一些设置为接触,使用checkPhysics()
函数显示将要发生的事情,然后让您随意切换这些形状
任何关于其工作原理的问题,我都很乐意尝试解释。看看这个:查找category bit mask的默认值。这里已经解释过了。指定一个物理体的collisionBitMAsk为4只意味着它与categoryBitMask为4的物理体发生碰撞(事实上,设置了'4'位,但让我们从最简单的示例开始)。如果您不想看到任何CategoryBitMask,事情就不会发生了。我不明白为什么我可以直接进入碰撞位掩码时,您需要类别位掩码?请您解释一下吗?好像不是
bowlingball.physicsBody?.collisionBitMask = basketballBitMask | bowlingballBitMask
// bowlingball collision bit mask (in binary) = 0b10 | 0b01 = 0b11
// bowlingball collision bit mask (in decimal) = 2 | 1 = 3
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