我深入研究了Apple SpriteKit和GameplayKit示例代码,发现了一个用Swift编写的名为“DemoBots”的项目。这些项目中使用了一些非常有趣的概念,我想将它们适应我的项目。
我已经在将冲突处理封装到处理程序类中,这与该示例代码中处理冲突的方式非常相似。
在这个项目中,我为名为RPColliderType
的结构找到了以下代码:
struct RPColliderType: OptionSetType, Hashable, CustomDebugStringConvertible {
// MARK: Static properties
/// A dictionary to specify which `ColliderType`s should be notified of contacts with other `ColliderType`s.
static var requestedContactNotifications = [RPColliderType: [RPColliderType]]()
/// A dictionary of which `ColliderType`s should collide with other `ColliderType`s.
static var definedCollisions = [RPColliderType: [RPColliderType]]()
// MARK: Properties
let rawValue: UInt32
// MARK: Options
static var Obstacle: RPColliderType { return self.init(rawValue: 1 << 0) }
static var PlayerBot: RPColliderType { return self.init(rawValue: 1 << 1) }
static var TaskBot: RPColliderType { return self.init(rawValue: 1 << 2) }
// MARK: Hashable
var hashValue: Int {
return Int(rawValue)
}
// MARK: SpriteKit Physics Convenience
/// A value that can be assigned to a 'SKPhysicsBody`'s `categoryMask` property.
var categoryMask: UInt32 {
return rawValue
}
/// A value that can be assigned to a 'SKPhysicsBody`'s `collisionMask` property.
var collisionMask: UInt32 {
// Combine all of the collision requests for this type using a bitwise or.
let mask = RPColliderType.definedCollisions[self]?.reduce(RPColliderType()) { initial, colliderType in
return initial.union(colliderType)
}
// Provide the rawValue of the resulting mask or 0 (so the object doesn't collide with anything).
return mask?.rawValue ?? 0
}
/// A value that can be assigned to a 'SKPhysicsBody`'s `contactMask` property.
var contactMask: UInt32 {
// Combine all of the contact requests for this type using a bitwise or.
let mask = RPColliderType.requestedContactNotifications[self]?.reduce(RPColliderType()) { initial, colliderType in
return initial.union(colliderType)
}
// Provide the rawValue of the resulting mask or 0 (so the object doesn't need contact callbacks).
return mask?.rawValue ?? 0
}
// MARK: ContactNotifiableType Convenience
/**
Returns `true` if the `ContactNotifiableType` associated with this `ColliderType` should be
notified of contact with the passed `ColliderType`.
*/
func notifyOnContactWithColliderType(colliderType: RPColliderType) -> Bool {
if let requestedContacts = RPColliderType.requestedContactNotifications[self] {
return requestedContacts.contains(colliderType)
}
return false
}
}
每当您设置
.collisionBitmask
的.contactBitmask
/.categoryBitmask
/SKPhysicsBody
属性时,都会使用此结构:class RPPhysicsComponent: GKComponent {
var physicsBody: SKPhysicsBody
init(physicsBody: SKPhysicsBody, colliderType: RPColliderType) {
self.physicsBody = physicsBody
self.physicsBody.categoryBitMask = colliderType.categoryMask
self.physicsBody.collisionBitMask = colliderType.collisionMask
self.physicsBody.contactTestBitMask = colliderType.contactMask
}
}
到现在为止还挺好。来自Objective-C,我的问题是我不完全理解RPColliderType Struct中的以下几行代码是做什么的:
/// A value that can be assigned to a 'SKPhysicsBody`'s `collisionMask` property.
var collisionMask: UInt32 {
// Combine all of the collision requests for this type using a bitwise or.
let mask = RPColliderType.definedCollisions[self]?.reduce(RPColliderType()) { initial, colliderType in
return initial.union(colliderType)
}
// Provide the rawValue of the resulting mask or 0 (so the object doesn't collide with anything).
return mask?.rawValue ?? 0
}
这是否意味着每次我调用该计算的属性(这就是它们 swift 调用的属性,对吗?)-当我将其分配给
SKPhysicsBody
时便会执行此操作-会将其添加到那些静态类字典中。但是我在解释“mask
”/“reduce
”/“union
”命令时遇到问题。真正的作用是什么?
最佳答案
collisionMask
是计算属性,返回的UInt32
值可用裁剪理物体的碰撞位掩码。如果将计算所得的属性分解为功能部分,则更容易理解。
但是首先,让我们将RPColliderType
应该与之发生冲突的PlayerBot
对象数组添加到definedCollisions
字典中:
RPColliderType.definedCollisions[.PlayerBot] = [.Obstacle, .TaskBot]
在这一点上,
definedCollisions
字典包含一个单独的项目,其PlayerBot
和[.Obstacle, .TaskBot]
分别为键和值。考虑一下这是因为可以与PlayerBot
冲突的类别是Obstacle
和TaskBot
。现在,我们可以使用
.PlayerBot
从字典中检索值(即数组):let array = RPColliderType.definedCollisions[.PlayerBot]
由于
collisionMask
是在RPColliderType
中定义的,因此self
用作字典键。另外,array
是可选的,因为在字典中可能不存在与键对应的值。然后,该代码使用
RPColliderType
方法将RPColliderType
对象数组组合为单个reduce
对象。 reduce
接受两个参数:一个初始值(与数组元素的类型相同)和一个将值作为参数并返回值的函数(或闭包)。在这种情况下,初始值是一个新的RPColliderType
对象,并且闭包的参数和返回值也是RPColliderType
对象:array?.reduce(RPColliderType(), aFunction)
Apple的代码使用结尾闭包,而不是将函数传递给
reduce
。从文档中reduce
遍历数组,并使用初始值和每个数组元素作为参数调用闭包,并将返回值用作下一次迭代的初始值:let mask = array?.reduce(RPColliderType()) {
initial, colliderType in
return initial.union(colliderType)
}
其中
initial
保留RPColliderType
数组元素的中间联合,而colliderType
是array
的当前元素。在这一点上,
mask
是一个RPColliderType
对象,我们可以使用mask?.rawValue
这是
UInt32
计算属性的返回值。