8

I am curious about a situation that I came across today when trying to unarchive and copy a SKSpriteNode from one SKScene to another. In the output from the playground below you can see that both linearDamping and angularDamping or not being maintained after the copy (they seem to be dropping back to default values)

// PLAYGROUND_SW1.2 - SKSpriteNode Copy
import UIKit
import SpriteKit

// ORIGINAL
let spriteNode = SKSpriteNode()
spriteNode.name = "HAPPY_NODE"
let size = CGSize(width: 55.0, height: 150.0)
let physics = SKPhysicsBody(rectangleOfSize: size)
physics.linearDamping = 0.123
physics.angularDamping = 0.456
spriteNode.physicsBody = physics

// COPY
let spriteCopy = spriteNode.copy() as! SKSpriteNode

// ORIGINAL
spriteNode.name
spriteNode.physicsBody?.linearDamping
spriteNode.physicsBody?.angularDamping
spriteNode.physicsBody?.area

// COPY
spriteCopy.name
spriteCopy.physicsBody?.linearDamping
spriteCopy.physicsBody?.angularDamping
spriteCopy.physicsBody?.area

PLAYGROUND OUTPUT enter image description here

I am not sure that I am copying this correctly, both SKSpriteNode and SKPhysicsBody conform to NSCopying If you look at the output above the area property is maintained after the copy and to my knowledge this is based on the size specified when the SKPhysicsBody was created.

Can anyone cast some light on this and maybe provide me with a pointer as to how I should be deep copying an SKSpriteNode?

Confused
  • 6,048
  • 6
  • 34
  • 75
fuzzygoat
  • 26,573
  • 48
  • 165
  • 294
  • 2
    Looks like a possible bug. [Have you filed one](http://bugreport.apple.com)? Have you tried separately copying the physics body? – rickster Feb 28 '15 at 19:57
  • Hi, I will try doing the physics Body copy and then submit a bug report if that fails too. I had not reported it yet because I wanted to make sure I was not missing something obvious before wasting Apples time. Much appreciated Sir. – fuzzygoat Mar 01 '15 at 08:30
  • If i create just a single SKPhysicsBody and try and copy it (I am using a playground) I get a SIGABRT, so something is definitely not right here. I will search the Apple site and submit a bug. – fuzzygoat Mar 02 '15 at 10:17
  • 1
    As no one other than Rickster has commented I have done as he suggests and filed a bug with Apple #20003803 – fuzzygoat Mar 04 '15 at 12:40

1 Answers1

12

I take one way to resolve your problem, probably is not the best way, but

   //COPY
   let spriteCopy = spriteNode.copy() as SKSpriteNode
   let physicsCopy:SKPhysicsBody = spriteNode.physicsBody!;

   ...
   //COPY PHYSICS BODY HARD MODE
   spriteCopy.physicsBody = physicsCopy;

To fix this problem, I created one extension, and @mogelbuster suggested override default copy(), ant it sounds great.

extension SKSpriteNode
{
    override open func copy() -> Any {
        let node = super.copy() as! SKSpriteNode;
        node.physicsBody = super.physicsBody;
        return node;
    }
}

With this extension you can do it, the default copy() method return Any because this you need cast to SKSpriteNode.

// COPY
let spriteCopy = spriteNode.copy() as! SKSpriteNode;

// ORIGINAL
spriteNode.name
spriteNode.physicsBody?.linearDamping
spriteNode.physicsBody?.angularDamping
spriteNode.physicsBody?.area


// COPY
spriteCopy.name
spriteCopy.physicsBody?.linearDamping
spriteCopy.physicsBody?.angularDamping
spriteCopy.physicsBody?.area

IMAGE

ViTUu
  • 1,204
  • 11
  • 21
  • 1
    Great answer! An extension on SKSpriteNode is definitely the way to go. Would it be better to override the original `copy()` method and call `super`'s implementation (like in initializers) instead of making a new `copyWithPhysicsBody()` method? – mogelbuster Mar 09 '17 at 04:35
  • 1
    @mogelbuster I changed the answer based on your tip. It is a nice observation, I liked this change. Thank you for the observation. – ViTUu Mar 10 '17 at 14:40
  • 1
    @Fattie You wouldnt want to do this anyway, this doesn't copy the `SKPhysicsBody`, it just assigns the copy node's physics body to the existing `SKPhysicsBody`, which I am guessing would either crash, or leave the original without a `SKPhysicsBody` – Knight0fDragon Oct 23 '17 at 14:39
  • i guess the guy's original three lines of code (right up the top) will really copy it - but yeah :/ By "does not work" I meant "does not copy the property values" as (I guess) you'd expect them to have had NSCopy do here ... – Fattie Oct 23 '17 at 15:13
  • You're not supposed to override properties/functions in swift extensions, you should read the docs. – Minimi Aug 24 '18 at 00:00
  • `node.physicsBody = super.physicsBody;` causes runtime error in Swift 5.3; changed to `node.physicsBody = super.physicsBody?.copy() as? SKPhysicsBody` worked. – Tien Do Apr 27 '21 at 12:24