sprite kit - How to interpret this Swift SpriteKit example code of a physics body bitmask system -
i taking deep apples spritekit & gameplaykit example code , found project called 'demobots' written in swift. there interesting concepts used in projects wanted adapt projects.
i working encapsulating collision-handling handler-class similar way collisions handled in example code.
in project found following code struct called rpcollidertype
:
struct rpcollidertype: optionsettype, hashable, customdebugstringconvertible { // mark: static properties /// dictionary specify `collidertype`s should notified of contacts other `collidertype`s. static var requestedcontactnotifications = [rpcollidertype: [rpcollidertype]]() /// dictionary of `collidertype`s should collide 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 /// value can assigned 'skphysicsbody`'s `categorymask` property. var categorymask: uint32 { return rawvalue } /// value can assigned 'skphysicsbody`'s `collisionmask` property. var collisionmask: uint32 { // combine of collision requests type using bitwise or. let mask = rpcollidertype.definedcollisions[self]?.reduce(rpcollidertype()) { initial, collidertype in return initial.union(collidertype) } // provide rawvalue of resulting mask or 0 (so object doesn't collide anything). return mask?.rawvalue ?? 0 } /// value can assigned 'skphysicsbody`'s `contactmask` property. var contactmask: uint32 { // combine of contact requests type using bitwise or. let mask = rpcollidertype.requestedcontactnotifications[self]?.reduce(rpcollidertype()) { initial, collidertype in return initial.union(collidertype) } // provide rawvalue of resulting mask or 0 (so object doesn't need contact callbacks). return mask?.rawvalue ?? 0 } // mark: contactnotifiabletype convenience /** returns `true` if `contactnotifiabletype` associated `collidertype` should notified of contact passed `collidertype`. */ func notifyoncontactwithcollidertype(collidertype: rpcollidertype) -> bool { if let requestedcontacts = rpcollidertype.requestedcontactnotifications[self] { return requestedcontacts.contains(collidertype) } return false } }
this struct used every time set .collisionbitmask
/ .contactbitmask
/ .categorybitmask
property of skphysicsbody
this: (i have implemented using component & entity design guide)
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 } }
so far good. coming objective-c problem not understand following lines of code out of rpcollidertype struct do:
/// value can assigned 'skphysicsbody`'s `collisionmask` property. var collisionmask: uint32 { // combine of collision requests type using bitwise or. let mask = rpcollidertype.definedcollisions[self]?.reduce(rpcollidertype()) { initial, collidertype in return initial.union(collidertype) } // provide rawvalue of resulting mask or 0 (so object doesn't collide anything). return mask?.rawvalue ?? 0 }
does mean every time call computed (that's called in swift, right?) property - when assign skphysicsbody
- adds static class dictionaries. have problem interpreting 'mask
' / 'reduce
' / 'union
' commands.
what do?
collisionmask
computed property returns uint32
value can used physics body's collision bit mask. it's easier understand how computed property works if broken down functional parts.
but first, let's add array of rpcollidertype
objects playerbot
should collide definedcollisions
dictionary:
rpcollidertype.definedcollisions[.playerbot] = [.obstacle, .taskbot]
at point, definedcollisions
dictionary contains single item playerbot
, [.obstacle, .taskbot]
key , value, respectively. think of categories can collide playerbot
obstacle
, taskbot
.
we can use .playerbot
retrieve value (i.e., array) dictionary:
let array = rpcollidertype.definedcollisions[.playerbot]
since collisionmask
defined in rpcollidertype
, self
used dictionary key. also, array
optional since value corresponding key may not exist in dictionary.
the code combines array of rpcollidertype
objects single rpcollidertype
object using reduce
method. reduce
takes 2 arguments: initial value (with same type elements of array) , function (or closure) takes value argument , returns value. in case, initial value new rpcollidertype
object , closure's argument , returned value rpcollidertype
objects:
array?.reduce(rpcollidertype(), afunction)
apple's code uses trailing closure instead of passing function reduce
. docs,
if need pass closure expression function function’s final argument , closure expression long, can useful write trailing closure instead. trailing closure closure expression written outside of (and after) parentheses of function call supports.
reduce
iterates on array , calls closure initial value , each array element arguments , returned value used initial value next iteration:
let mask = array?.reduce(rpcollidertype()) { initial, collidertype in return initial.union(collidertype) }
where initial
keeps intermediate union of rpcollidertype
array elements , collidertype
current element of array
.
at point, mask
rpcollidertype
object can convert uint32
with
mask?.rawvalue
which returned value of collisionmask
computed property.
Comments
Post a Comment