2016-01-27 11 views
5

मैं एप्पल स्प्राइटकिट & गेमप्लेकिट उदाहरण कोड में गहराई से देख रहा था और स्विफ्ट में लिखे गए 'डेमोबॉट्स' नामक एक परियोजना मिली। उन परियोजनाओं में उपयोग की जाने वाली कुछ बहुत ही रोचक अवधारणाएं हैं जिन्हें मैं अपनी परियोजनाओं में अनुकूलित करना चाहता था।इस स्विफ्ट स्प्राइटकिट का वर्णन कैसे करें भौतिकी निकाय बिटमैस्क सिस्टम का उदाहरण कोड

मैं पहले से ही एक हैंडलर-क्लास में टक्कर-हैंडलिंग को समाहित करने के साथ काम कर रहा था जो उस उदाहरण कोड में टकरावों के तरीके के समान ही है।

इस परियोजना में मैंने पाया एक struct के लिए निम्न कोड 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 
    } 
} 

यह struct आप एक SKPhysicsBody इस तरह की .collisionBitmask/.contactBitmask/.categoryBitmask गुण सेट हर बार प्रयोग किया जाता है: (मैं लागू कर दिया है इस घटक & इकाई डिजाइन मार्गदर्शिका का उपयोग करके)

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

अब तक तो अच्छा।

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

कि मतलब यह है कि हर बार जब मैं फोन है, जिसकी गणना (है कि वे क्या कहा जाता है है: ऑब्जेक्टिव-सी से आ मेरी समस्या यह है कि मैं पूरी तरह से समझ में नहीं आता क्या RPColliderType Struct से बाहर कोड के उन लोगों के निम्नलिखित लाइनों करना है तेजी से, सही?) संपत्ति - मैं इसे करता हूं जब मैं इसे SKPhysicsBody पर असाइन करता हूं - यह इसे उन स्थिर वर्ग शब्दकोशों में जोड़ता है। लेकिन मुझे 'mask'/'reduce'/'union' आदेशों की व्याख्या करने में समस्या है।

वास्तव में ऐसा क्या करता है?

उत्तर

2

collisionMask गणना की गई संपत्ति है जो UInt32 मान देता है जिसे भौतिकी निकाय के टक्कर बिट मास्क के रूप में उपयोग किया जा सकता है। यह समझना आसान है कि यह गणना की गई संपत्ति कैसे काम करती है यदि यह अपने कार्यात्मक भागों में टूट जाती है।

लेकिन पहले, के RPColliderType वस्तुओं कि PlayerBotdefinedCollisions शब्दकोश में साथ भिड़ना चाहिए की एक सरणी जोड़ने: इस बिंदु पर

RPColliderType.definedCollisions[.PlayerBot] = [.Obstacle, .TaskBot] 

, definedCollisions शब्दकोश PlayerBot और [.Obstacle, .TaskBot] के रूप में के साथ एक एकल आइटम शामिल है क्रमशः कुंजी और मूल्य। इस बारे में सोचें कि PlayerBot के साथ टकराने वाली श्रेणियां Obstacle और TaskBot हैं।

अब हम शब्दकोश से मूल्य (अर्थात, सरणी) को पुनः प्राप्त करने .PlayerBot उपयोग कर सकते हैं:

let array = RPColliderType.definedCollisions[.PlayerBot] 

collisionMask के बाद से RPColliderType में परिभाषित किया गया है, self शब्दकोश कुंजी के रूप में प्रयोग किया जाता है। इसके अलावा, array एक वैकल्पिक है क्योंकि कुंजी से संबंधित मान शब्दकोश में मौजूद नहीं हो सकता है।

कोड तब ऑब्जेक्ट्स को विधि का उपयोग कर RPColliderType ऑब्जेक्ट में ऑब्जेक्ट को जोड़ता है। reduce दो तर्क लेता है: प्रारंभिक मान (सरणी के तत्वों के समान प्रकार के साथ) और एक फ़ंक्शन (या बंद) जो एक तर्क के रूप में मान लेता है और एक मान देता है।

array?.reduce(RPColliderType(), aFunction) 

एप्पल के कोड के बजाय reduce करने के लिए एक समारोह में उत्तीर्ण होने की पीछे बंद का उपयोग करता है: इस मामले में, प्रारंभिक मूल्य एक नया RPColliderType वस्तु और बंद होने के तर्क और दिए गए मान भी RPColliderType वस्तुओं रहे है। डॉक्स से,

आप समारोह के अंतिम तर्क के रूप में एक समारोह और बंद अभिव्यक्ति लंबा है करने के लिए एक बंद अभिव्यक्ति पारित करने के लिए की जरूरत है, यह उपयोगी है कि यह एक अनुगामी बंद के रूप में के बजाय लिखने के लिए हो सकता है। एक पिछला बंद एक बंद अभिव्यक्ति है जो है जो फ़ंक्शन कॉल के कोष्ठक के बाहर (और उसके बाद) लिखा गया है।

let mask = array?.reduce(RPColliderType()) { 
    initial, colliderType in 
    return initial.union(colliderType) 
} 

जहां initial रखता है: सरणी पर

reduce दोहराता और प्रारंभिक मूल्य और तर्क के रूप में प्रत्येक सरणी तत्व और दिए गए मान के साथ बंद कॉल अगले चरण के लिए प्रारंभिक मूल्य के रूप में प्रयोग किया जाता है RPColliderType सरणी तत्वों का इंटरमीडिएट यूनियन और colliderTypearray का वर्तमान तत्व है।

इस बिंदु पर, mask एक RPColliderType उद्देश्य यह है कि हम

mask?.rawValue 

जो collisionMask परिकलित प्रॉपर्टी के दिए गए मान के साथ एक UInt32 में कन्वर्ट कर सकते हैं।

+0

इस तरह के विस्तृत स्पष्टीकरण के लिए धन्यवाद। लगभग कुछ ऐसा है जैसे आपने उदाहरण कोड का टुकड़ा लिखा है !? तथापि। मेरी समझ से यह कोड का एक बहुत ही सुरुचिपूर्ण टुकड़ा है, है ना? –

+0

आपका स्वागत है। यह कोड श्रेणी, टकराव और संपर्क बिट मास्क प्रबंधित करने के लिए 'OptionSetType' का उपयोग करने का एक अच्छा उदाहरण है। – 0x141E

संबंधित मुद्दे