How to copy SKSpriteNode with SKPhysicsBody?
Asked Answered
C

1

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?

Closet answered 26/2, 2015 at 10:32 Comment(4)
Looks like a possible bug. Have you filed one? Have you tried separately copying the physics body?Greyso
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.Closet
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.Closet
As no one other than Rickster has commented I have done as he suggests and filed a bug with Apple #20003803Closet
F
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

Flatworm answered 5/3, 2015 at 17:37 Comment(6)
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?Cns
@Cns I changed the answer based on your tip. It is a nice observation, I liked this change. Thank you for the observation.Flatworm
@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 SKPhysicsBodyBison
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 ...Commodus
You're not supposed to override properties/functions in swift extensions, you should read the docs.Sardou
node.physicsBody = super.physicsBody; causes runtime error in Swift 5.3; changed to node.physicsBody = super.physicsBody?.copy() as? SKPhysicsBody worked.Ossein

© 2022 - 2024 — McMap. All rights reserved.