swiftsprite-kitskspritenodeskphysicsbodyspawning

SpriteKit, copying a physics body does NOT copy the settings?


It seems almost incredible but,

let pb = model.physicsBody?.copy() as! SKPhysicsBody
print("orig .. \(model.physicsBody!.linearDamping)")
print("pb .. \(pb.linearDamping)")

they are NOT the same. No really.

This is so bizarre that I must be doing something wrong. What am I doing wrong?

Other than just manually copying all the properties, and maintaining the code forever as that evolves, how to do this??


Here's a dupe-qualities function if anyone needs it, to save typing. (This of 2017 - of course it has to be maintained forever as Apple add qualities.)

extension SKSpriteNode
{
    func dupe() -> Any {

        // annoyingly, Apple does not provide a dupe function as you would use
        // when spawning from a model.

        let c = self.copy() as! SKSpriteNode

        c.physicsBody = self.physicsBody!.copy() as? SKPhysicsBody

        c.physicsBody?.affectedByGravity = self.physicsBody!.affectedByGravity
        c.physicsBody?.allowsRotation = self.physicsBody!.allowsRotation
        c.physicsBody?.isDynamic = self.physicsBody!.isDynamic

        c.physicsBody?.pinned = self.physicsBody!.pinned

        c.physicsBody?.mass = self.physicsBody!.mass
        c.physicsBody?.density = self.physicsBody!.density
        c.physicsBody?.friction = self.physicsBody!.friction
        c.physicsBody?.restitution = self.physicsBody!.restitution
        c.physicsBody?.linearDamping = self.physicsBody!.linearDamping
        c.physicsBody?.angularDamping = self.physicsBody!.angularDamping

        c.physicsBody?.categoryBitMask = self.physicsBody!.categoryBitMask
        c.physicsBody?.collisionBitMask = self.physicsBody!.collisionBitMask
        c.physicsBody?.fieldBitMask = self.physicsBody!.fieldBitMask
        c.physicsBody?.contactTestBitMask = self.physicsBody!.contactTestBitMask

        return c
    }
}

(Just one man's opinion, I feel it's better to not just override the NSCopy, since, the whole thing is a touchy issue and it's probably better to simply be explicit for the sake of the next engineer. It's very common to "dupe" the qualities of a game object to another, so, this is fine.)


Solution

  • It has to do with SKPhysicsBody being a wrapper class to PKPhysicsBody

    Essentially what is going on is when you create a copy of SKPhysicsBody, it creates a new instance of PKPhysicsBody, not a copy of it.

    To get around this, you need to write an extension that fills in the values for you:

    extension SKPhysicsBody
    {
        override open func copy() -> Any {
            guard let body = super.copy() as? SKPhysicsBody else {fatalError("SKPhysicsBody.copy() failed")}
            body.affectedbyGravity = affectedByGravity
            body.allowsRotation= allowsRotation
            body.isDynamic= isDynamic
            body.mass= mass
            body.density = density
            body.friction = friction
            body.restitution = restitution
            body.linearDamping = linearDamping
            body.angularDamping = angularDamping
    
            return body
        }
    }
    

    Note, I typed this by hand, I do not have XCode available at this time to test if it does work.