使用SpriteKit阻止对象发生碰撞

时间:2016-10-30 18:51:00

标签: swift sprite-kit

我正在测试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)
}

因此对象的位掩码为4:

object.physicsBody?.collisionBitMask = UInt32(4)

第二个位掩码为1:

second.physicsBody?.collisionBitMask = UInt32(1)

我跑了模拟器,他们仍然相互碰撞,所以我上网并试图寻找答案:我找到了一个说我必须使用的数字:

  

这些是位掩码,你不能使用任意数字1,2,3,4,5 - 你必须使用1,2,4,8,16等等 -

有人可以解释原因吗?但是,这不是问题,因为我使用的是1和4

我遇到的下一个问题说我必须使用二进制数字(0100)和(0010),我试过它们,同样的问题:仍然发生碰撞。

我将留下碰撞图片: Collisions

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

2 个答案:

答案 0 :(得分:8)

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

categoryBitMasks的力量

假设您有三个节点poolbasketballbowlingball的集合。现在,显然,我们希望basketballbowlingball相互冲突。所以你像这样设置collisionBitMasks:

basketball.physicsBody?.collisionBitMask    = UInt32(2)
bowlingball.physicsBody?.collisionBitMask   = UInt32(2)

大。现在,我们希望bowlingball下沉到pool的底部,basketballpool发生碰撞(可能更多的是引起轰动,但要忍受我)。我们怎么做?我们可以试试:

pool.physicsBody?.collisionBitMask = UInt32(2) // ?

但请稍等,这会使basketballbowlingballpool发生冲突。我们只希望basketball与池冲突,而我们希望bowlingball忽略pool并直接沉到底部而不会发生冲突。这是categoryBitMask派上用场的地方:

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

如果你不确定那些奇怪的&#39; |&#39;符号正在做,我强烈推荐高级操作符swift documentation来帮助您了解这里发生的事情。

为什么不使用collisionBitMasks?

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

简单地说,这不是它的工作原理。当bowlingballpool联系时,SpriteKit物理引擎会将bowlingball categoryBitMask 与pool的collisionBitMask(反之亦然;结果相同):

objectsShouldCollide = (bowlingball.physicsBody?.categoryBitMask & 
                        pool.physicsBody?.collisionBitMask)
// objectsShouldCollide = (ob010 & 0b100) = 0b000 

由于bowlingball categoryBitMaskpool&#39; s collisionBitMask共有零位,objectsShouldCollide相等为零,SpriteKit将阻止物体碰撞。

但是,在您的情况下,您并未设置对象&#39; categoryBitMask秒。因此它们的默认值为2 ^ 32或0xFFFFFFFF(hexadecimal representation)或二进制,0b1111111111111111111111111111111111。所以当一个&#34;对象&#34;击中第二个&#34;对象,SpriteKit这样做:

objectsShouldCollide = (0b11111111111111111111111111111111 & // Default categoryBitMask for "object" 
                        0b00000000000000000000000000000001)  // collisionBitMask for "second" object
//                   =  0b00000000000000000000000000000001

因此,当您没有定义object的categoryBitMask时,无论您设置为second对象collisionBitMask,objectShouldCollide都会永远不会为零,他们总会碰撞。

注意:您可以将对象的collisionBitMask设置为0;但那个对象永远不会与任何东西发生碰撞。

对categoryBitMasks

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

现在让我们说我们想要包含多个相互碰撞的bowlingball个。易:

bowlingball.physicsBody?.collisionBitMask  = basketballBitMask | bowlingballBitMask
// bowlingball collision bit mask (in binary)  = 0b10 | 0b01 = 0b11
// bowlingball collision bit mask (in decimal)  = 2 | 1 = 3 

在这里你可以看到,如果我们将pool的physicsCategory设置为UInt32(3),它就不再能与bowlingballbasketball区分开。

进一步的建议

有目的地学习name变量,即使您只是使用它们进行测试(但巧合的是,&#34; objectsecond对象&#34;工作得很好。)

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

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

答案 1 :(得分:2)

为什么不下载并使用这个简单的Sprite-Kit项目?它会创建各种几何形状,将其中一些设置为碰撞,一些设置为接触,使用#import <UIKit/UIKit.h> @interface AddressListTableViewCell : UITableViewCell @property (weak, nonatomic) IBOutlet UIView *viewAddressInfo; @property (weak, nonatomic) IBOutlet UILabel *labelUsername; @property (weak, nonatomic) IBOutlet UILabel *labelAddress; @property (weak, nonatomic) IBOutlet UIImageView *imageViewRadioSelection; @end 功能显示将要发生的事情,然后让您轻弹它们。

Attack button in SpriteKit

对于它的运作有任何疑问,我会非常乐意尝试解释。