1

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.)

Fattie
  • 27,874
  • 70
  • 431
  • 719
  • It has to do with SKPhysicsBody being a wrapper class to PKPhysicsBody, they poorly implemented how this works, where SKPhysicsBody copies, but it creates a new PKPhysicsBody. You may be able to extend and override the copy function to fix it – Knight0fDragon Oct 23 '17 at 14:06
  • anyway it's good to know that, factually, it does NOT copy the values, it does not clone :/ I guess that's life – Fattie Oct 23 '17 at 14:21
  • Another issue I noticed with physics body in iOS is, you cannot just "change between" the categories (volume/edge etc). That is not unreasonable, but really, for me it is remarkably confusing they made them the same class, in that case. It should just be SKPhysicsBody (ie, "A body") and SKPhysicsTrigger - or whatever else they have. – Fattie Oct 23 '17 at 14:23
  • There is no typo, `PKPhysicsBody` is from `PhysicsKit`, a private framework that we do not have access to. `SKPhysicsBody` creates a `PKPhysicsBody` entity, so when you do copy. it is creating a new `PKPhysicsBody` entity, not copying the existing one. – Knight0fDragon Oct 23 '17 at 14:23
  • Ah! Beg your pardon I didn't note the *P* - thanks, awesome – Fattie Oct 23 '17 at 14:25
  • E.g. When you call `body.linearDamping`, it is really calling `body.pkbody.linearDamping` – Knight0fDragon Oct 23 '17 at 14:25
  • why oh why didn't they just buy a PhysX license :) – Fattie Oct 23 '17 at 14:25
  • it uses a fork of Box2D – Knight0fDragon Oct 23 '17 at 14:26
  • I see ... :/ fair enough – Fattie Oct 23 '17 at 14:26
  • Does it ultimately use the GPUs !?! It is Metal right, not ogl.. – Fattie Oct 23 '17 at 14:27
  • I don't know, i do not think the physics engine touches the GPU at all, but that is too low level for me to investigate. – Knight0fDragon Oct 23 '17 at 14:28
  • Perhaps you should put in your answer (basically "No - because of PK") to help googlers, you know. Funny, over in India "pk" is slang for "tipsy, drunk" :) – Fattie Oct 23 '17 at 14:29
  • You know, since spritekit physics runs really badly in simulator - maybe that suggests they are indeed using the GPU for processing. – Fattie Oct 23 '17 at 16:04
  • simulator is 100% CPU i believe, no hardware acceleration at all – Knight0fDragon Oct 23 '17 at 16:05
  • Right - hence, maybe the physics in SpriteKit DOES use the gpu: if you see what I mean. Anyways ... – Fattie Oct 23 '17 at 16:11
  • lol no, I mean we do not know if it is the physics that are slow, or if it is the graphic computations causing it to be slow since it is 100% CPU. Regardless, it is what it is, we are at the whim of whatever Apple engineers decide to do with their library. – Knight0fDragon Oct 23 '17 at 16:14
  • Right, I get you - true enough :) – Fattie Oct 23 '17 at 16:15

1 Answers1

1

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.

Knight0fDragon
  • 16,609
  • 2
  • 23
  • 44
  • it's good to know that the factual answer is, Apple does NOT deep copy in this case. good one. – Fattie Oct 29 '17 at 16:03