使用SpriteKit阻止对象发生碰撞

Pab*_*blo 11 sprite-kit swift

我正在测试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),我试过它们,同样的问题:仍然发生冲突.

我将留下碰撞的图片: 碰撞

有谁知道为什么会这样?如果这是一个非常愚蠢的错误或已经被问到的事情,我提前道歉,我就是找不到它.

Ral*_*lph 8

关于这些主题有很多文档,但这是一个实际的例子.

categoryBitMasks的力量

假装你有三个节点的集合pool,basketballbowlingball.现在,显然,我们希望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?

好的,所以我们设置了一些位掩码.但他们是如何使用的呢?如果我们只有两个对象,为什么我们不能只比较collisionBitMasks?

简单地说,这不是它的工作原理.当bowlingball接触到接触pool时,SpriteKit物理学引擎将AND("&")一起bowlingballcategoryBitMaskpool的collisionBitMask(或反之亦然;其结果是一样的):

objectsShouldCollide = (bowlingball.physicsBody?.categoryBitMask & 
                        pool.physicsBody?.collisionBitMask)
// objectsShouldCollide = (ob010 & 0b100) = 0b000 
Run Code Online (Sandbox Code Playgroud)

因为bowlingball's categoryBitMaskpool'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; 但是那个物体永远无法与任何东西发生碰撞.

对categoryBitMasks使用2(0,1,2,4,8等)的幂

现在让我们说我们想要包含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 bowlingballbasketball.

进一步建议

学习有目的地命名变量,即使你只是用它们进行测试(虽然,巧合的是," objectsecond对象"工作得很好).

使用位掩码结构来简化代码并提高可读性:

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)