了解SpriteKit CollisionBitMask

Giz*_*zGo 0 xcode sprite-kit swift

我正在学习使用SpriteKit,我正在学习colllisions教程.我正在努力理解以下代码:

struct PhysicsCategory {
  static let None      : UInt32 = 0
  static let All       : UInt32 = UInt32.max
  static let Monster   : UInt32 = 0b1       // 1
  static let Projectile: UInt32 = 0b10      // 2
}
Run Code Online (Sandbox Code Playgroud)

为什么我们要分配这些被调用的东西bitMaps以及它们如何在下面的代码中工作?:

func didBegin(_ contact: SKPhysicsContact) {

    // 1
    var firstBody: SKPhysicsBody
    var secondBody: SKPhysicsBody
    if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
        firstBody = contact.bodyA
        secondBody = contact.bodyB
    } else {
        firstBody = contact.bodyB
        secondBody = contact.bodyA
    }

    // 2
    if ((firstBody.categoryBitMask & PhysicsCategory.Monster != 0) &&
        (secondBody.categoryBitMask & PhysicsCategory.Projectile != 0)) {
        if let monster = firstBody.node as? SKSpriteNode, let
            projectile = secondBody.node as? SKSpriteNode {
            projectileDidCollideWithMonster(projectile: projectile, monster: monster)
Run Code Online (Sandbox Code Playgroud)

谢谢!

Kni*_*gon 6

BitMasks是用于描述二进制格式的项目的标志

所以想象你有8种方式来描述某些东西.(在Spritekit中你有32个)

我们可以将这8个东西组合成一个字节,因为8位是一个字节,这样我们就可以节省空间并更快地执行操作.

以下是8个描述的示例

Attackable 1 << 0  
Ranged     1 << 1  
Undead     1 << 2  
Magic      1 << 3  
Regenerate 1 << 4  
Burning    1 << 5  
Frozen     1 << 6  
Poison     1 << 7  
Run Code Online (Sandbox Code Playgroud)

现在我有一个射手,想要归类他.我想说他是一个生活友好的单位

我会用它categoryBitmask来分类他:

archer.categoryBitmask = Ranged

这将以1字节表示为

00000010
||||||||_ Attackable
|||||||_ Ranged
||||||_ Undead
|||||_ Magic
||||_ Regenerate
|||_ Burning
||_ Frozen
|_ Poison
Run Code Online (Sandbox Code Playgroud)

现在让我们说他的箭是火箭,我会把它归类为:

arrow.categoryBitmask = Burning

00100000
||||||||_ Attackable
|||||||_ Ranged
||||||_ Undead
|||||_ Magic
||||_ Regenerate
|||_ Burning
||_ Frozen
|_ Poison
Run Code Online (Sandbox Code Playgroud)

最后,我们有一个可以被击中并随着时间的推移再生的僵尸

zombie.categoryBitmask = Attackable + Undead + Regenerate

00010101
||||||||_ Attackable
|||||||_ Ranged
||||||_ Undead
|||||_ Magic
||||_ Regenerate
|||_ Burning
||_ Frozen
|_ Poison
Run Code Online (Sandbox Code Playgroud)

现在我希望我的箭头只能击中Attackable精灵(在这种情况下是僵尸)

我会设置contactTestBitmask告诉箭头他能击中什么

arrow.contactTestBitmask = Attackable 00000001
Run Code Online (Sandbox Code Playgroud)

现在我们需要检查箭头何时击中僵尸,这就是didBeginContact进入的地方

什么didBeginContact都行,就是检查contactTestBitmask运动项目的categoryBitmask,碰撞通过使用与操作,以找到一个匹配

在我们的例子中

arrow.contactTestBitmask =  00000001
zombie.categoryMask      =  00010101 AND
                            --------
                            00000001
Run Code Online (Sandbox Code Playgroud)

由于我们的值> 0,因此联系成功.

这意味着doBegins被解雇了.

现在我们在didBegins,我们需要确定哪个物理体是我们的箭头,哪个物理体是我们的僵尸

这是下一个声明的来源

func didBegin(_ contact: SKPhysicsContact) {

    // 1
    var firstBody: SKPhysicsBody
    var secondBody: SKPhysicsBody
    if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
        firstBody = contact.bodyA
        secondBody = contact.bodyB
    } else {
        firstBody = contact.bodyB
        secondBody = contact.bodyA
}
Run Code Online (Sandbox Code Playgroud)

由于箭头= 00100000和zombie = 00010101,我们知道僵尸的值比箭头低,所以在这种情况下,僵尸是<箭头.

我们分配firstBody给僵尸和secondBody箭头

现在我们需要提供一个条件.

我们想说一个不死生物是否被可燃物体击中,做一些事情.

所以在代码中这将是

if (firstBody & Undead > 0) && (secondBody & Burning > 0)
{
//burn zombie
}
Run Code Online (Sandbox Code Playgroud)

但是如果箭头是冰箭呢?我们不想进入if声明.

那么现在我们可以添加第二个条件,让我们冻结僵尸.

if (firstBody & Undead > 0) && (secondBody & Frozen > 0)
{
//freeze zombie
}
Run Code Online (Sandbox Code Playgroud)

这些ifs正在做什么,是确保身体已打开某些功能,然后执行一些操作以响应它们.

要了解有关位掩码如何工作的更多信息,我将研究如何制作真值表.这基本上就是这个.我们只是创建一些真值表,并试图弄清楚一个陈述是否为真,如果是真,则执行一个动作.