使用 SpriteKit 阻止对象碰撞 [英] Stop objects from colliding using SpriteKit

查看:29
本文介绍了使用 SpriteKit 阻止对象碰撞的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在测试 SpriteKit 的功能,但遇到了问题.我正在阅读位掩码、碰撞、类别和联系.我知道它们是什么,至少,我不明白类别位掩码的意义,但是我得到了冲突位掩码,这是我解决问题所需要的.

I am testing out the features of SpriteKit and I ran into a problem. I was reading into bit masks, colliding, category, and contact. I get what they are, mostly at least, I don't get the point of category bitmasks, but I get colliding bitmasks which are the ones I need to solve my problem.

好的,所以我的问题是我有两种不同类型的精灵:objectsecond. 名称并没有多大意义,但这只是为了的测试.我想让第二个有冲动,我想让对象有一种力量.我能够在精灵上应用各自的向量,但我不希望它们相互碰撞.我希望他们直接通过,忽略彼此的存在.

Ok so my problem is I have two different types of sprites: object and second. The names don't really make much sense but it is just for the sake of testing. I want second to have an impulse, and I want object to have a force. I was able to apply the respective vectors on the sprites, but I do not want them to collide with each other. I want them to pass right through and ignore the existence of each other.

我试图通过相互分配不同的冲突位掩码来解决这个问题:

I tried to solve that issue by assigning different collision bitmasks to each other:

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:

So object has a bitmask of 4:

object.physicsBody?.collisionBitMask = UInt32(4)

第二个位掩码为 1:

second.physicsBody?.collisionBitMask = UInt32(1)

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

I ran the simulator and they are still colliding with each other, so I went online and tried to look for some answers: I found one that says I must use numbers like:

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

these are bitmasks, you can't use arbitrary numbers 1,2,3,4,5 - you must use 1,2,4,8,16 and so on –

有人能解释为什么吗?但是,这不是问题,因为我使用的是 1 和 4

Can someone explain why? However, that wasn't the issue because I was using 1 and 4

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

Next question I ran into said that I had to use binary numbers (0100) and (0010), I tried them, same issue: still colliding.

我会留下碰撞的照片:碰撞

有人知道为什么会这样吗?如果这是一个非常愚蠢的错误或已经问过的问题,我提前道歉,我只是找不到它.

Does anyone know why this is happening? My apologies in advance if this is a really dumb mistake or something that has already been asked, I just couldn't find it.

推荐答案

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

There is a lot of documentation on these topics, but here is a practical example.

假设您有一个由 poolbasketballbowlingball 三个节点组成的集合.现在,很明显,我们希望 basketballbowlingball 相互碰撞.所以你像这样设置collisionBitMasks:

Pretend you have a collection of three nodes pool, basketball and bowlingball. Now, obviously, we want the basketball and bowlingball to collide with the each other. So you set the collisionBitMasks like so:

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

太好了.现在,我们希望 bowlingball 沉到 pool 的底部,并且 basketballpool 碰撞>(可能更多的是飞溅,但请耐心等待).我们将如何做到这一点?我们可以试试:

Great. Now, we want the bowlingball to sink to the bottom of the pool, and the basketball to collide with the pool (might be more of a splash, but bear with me). How would we do this? We could try:

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

但是等等,这会使 basketballbowlingballpool 发生碰撞.我们只希望 basketball 与水池发生碰撞,而我们希望 bowlingball 忽略 pool 并直接沉入底部而不会发生碰撞.这就是 categoryBitMask 派上用场的地方:

But wait, that would make the basketball AND the bowlingball collide with the pool. We only want the basketball to collide with the pool , whereas we want the bowlingball to ignore the pool and sink straight to the bottom with no collisions. This is where categoryBitMasks come in handy:

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

因为每个对象都有一个唯一的编号,您现在可以选择您希望另一个对象与哪些对象发生碰撞:

Because each object has a unique number assigned to it, you can now pick and choose which objects you'd like another object to collide with:

// 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

如果你不确定奇怪的 '|' 是什么符号正在做,我强烈推荐 swift 文档 介绍高级运算符,以帮助您了解这里发生的情况.

If you're not sure what the strange '|' symbol is doing, I highly recommend the swift documentation on advanced operators to help you understand what's happening here.

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

Okay so we've set some bit masks. But how are they used? If we only have two objects why can't we just compare collisionBitMasks?

简单地说,这不是它的工作原理.当 bowlingballpool 接触时,SpriteKit 物理引擎会将 bowlingballcategoryBitMaskpool 的 collisionBitMask(反之亦然;结果相同):

Simply put, that's just not how it works. When a bowlingball comes into contact with the pool, the SpriteKit physics engine will AND ('&') together the bowlingball's categoryBitMask with the pool's collisionBitMask (or vice versa; the result is the same):

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

因为 bowlingballcategoryBitMaskpoolcollisionBitMask 共有零位,objectsShouldCollide 等于 0,SpriteKit 会阻止物体碰撞.

Because the bowlingball's categoryBitMask and the pool's collisionBitMask have zero bits in common, objectsShouldCollide is equal to zero, and SpriteKit will stop the objects from colliding.

但是,在您的情况下,您没有设置对象的 categoryBitMask.因此它们的默认值为 2^32,或 0xFFFFFFFF(十六进制表示)或二进制,0b1111111111111111111111111111111.所以当一个物体"碰到一个第二个"物体时,SpriteKit 会这样做:

But, in your case, you're not setting your objects' categoryBitMasks. So they have a default value of 2^32, or 0xFFFFFFFF (hexadecimal representation) or in binary, 0b11111111111111111111111111111111. So when an "object" hits a "second" object, SpriteKit does this:

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

所以当你还没有定义object的categoryBitMask时,无论你将second对象的collisionBitMask设置成什么,objectsShouldCollide都会永远不会为零,它们总是会发生碰撞.

So when you haven't defined the object's categoryBitMask, no matter what you set as the second object's collisionBitMask, objectsShouldCollide will never be zero, and they will always collide.

注意:您可以将对象的 collisionBitMask 设置为 0;但是那个物体将永远无法与任何东西发生碰撞.

Note: you could set an object's collisionBitMask to 0; but then that object would never be able to collide with anything.

现在假设我们想要包含多个相互碰撞的 bowlingball.简单:

Now let's say we wanted to include multiple bowlingballs that collided with each other. Easy:

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

在这里您可以看到,如果我们将 pool 的物理类别设置为 UInt32(3),它将不再与 bowlingballbasketball 区分开来.

Here you can see that if we had set the pools physicsCategory to UInt32(3), it would no longer be distinguishable from a bowlingball or basketball.

学习名称 有目的的变量,即使您只是将它们用于测试(尽管巧合的是,objectsecond object"效果很好).

Learn to name variables with purpose, even if you're just using them for testing (although, coincidentally, "object and second object" worked quite well).

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

Use a struct for bitmasks to simplify your code and improve readability:

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

这篇关于使用 SpriteKit 阻止对象碰撞的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆