位掩码的原因是它使您/程序能够轻松快速地计算两个对象之间是否发生碰撞。因此:是的这是某种优化。
假设我们有这三个类别
- 导弹
0x1 << 0
- 玩家
0x1 << 1
- 墙
0x1 << 2
现在我们有一个Player 实例,它的类别设置为player。它的碰撞位掩码设置为missile | player | wall(+ 而不是| 也可以),因为我们希望能够与所有三种类型发生碰撞:其他玩家、关卡墙壁和飞来飞去的子弹/导弹。
现在我们有一个Missile,类别设置为missile,碰撞位掩码设置为player | wall:它不会与其他导弹碰撞,而是会击中玩家和墙壁。
如果我们现在想要评估两个对象是否可以相互碰撞,我们将获取第一个对象的类别位掩码和第二个对象的碰撞位掩码,然后简单地 & 它们:
上述设置在代码中如下所示:
let player : UInt8 = 0b1 << 0 // 00000001 = 1
let missile : UInt8 = 0b1 << 1 // 00000010 = 2
let wall : UInt8 = 0b1 << 2 // 00000100 = 4
let playerCollision = player | missile | wall // 00000111 = 7
let missileCollision = player | wall // 00000101 = 5
后面的推理基本上是:
if player & missileCollision != 0 {
print("potential collision between player and missile") // prints
}
if missile & missileCollision != 0 {
print("potential collision between two missiles") // does not print
}
我们在这里使用了一些位运算,每个位代表一个类别。
您可以简单地枚举位掩码 1,2,3,4,5...,但是您无法对它们进行任何数学运算。因为您不知道作为类别位掩码的 5 是否真的是类别 5,或者它是类别 1 和类别 4 的对象。
但是,仅使用位我们可以做到这一点:就 7 的 2 的幂而言,唯一的表示是 4 + 2 + 1:因此,任何具有冲突位掩码 7 的对象都会与类别 4、2 和 1 发生冲突。一个位掩码为 5 的正是类别 1 和类别 4 的组合 - 没有其他方法。
现在,由于我们不枚举 - 每个类别使用一位,而常规整数只有 32(或 64)位,我们只能有 32(或 64)个类别。
看看以下更广泛的代码,它演示了如何在更一般的术语中使用掩码:
let playerCategory : UInt8 = 0b1 << 0
let missileCategory : UInt8 = 0b1 << 1
let wallCategory : UInt8 = 0b1 << 2
struct EntityStruct {
var categoryBitmask : UInt8
var collisionBitmask : UInt8
}
let player = EntityStruct(categoryBitmask: playerCategory, collisionBitmask: playerCategory | missileCategory | wallCategory)
let missileOne = EntityStruct(categoryBitmask: missileCategory, collisionBitmask: playerCategory | wallCategory)
let missileTwo = EntityStruct(categoryBitmask: missileCategory, collisionBitmask: playerCategory | wallCategory)
let wall = EntityStruct(categoryBitmask: wallCategory, collisionBitmask: playerCategory | missileCategory | wallCategory)
func canTwoObjectsCollide(first:EntityStruct, _ second:EntityStruct) -> Bool {
if first.categoryBitmask & second.collisionBitmask != 0 {
return true
}
return false
}
canTwoObjectsCollide(player, missileOne) // true
canTwoObjectsCollide(player, wall) // true
canTwoObjectsCollide(wall, missileOne) // true
canTwoObjectsCollide(missileTwo, missileOne) // false
这里的重要部分是canTwoObjectsCollide 方法不关心对象的类型或有多少类别。只要您坚持使用位掩码,您就可以确定两个对象在理论上是否会发生碰撞(忽略它们的位置,这是另一天的任务)。