4
votes

I'm attempting to take advantage of the init?(coder aDecoder: NSCoder) function so that I can subclass sprites in my sks file.

I can set the physics body in the sks file, but it doesn't work too well with my rectangular sprites I'm using that also have rounded corners. Because of the rounded corners, prior to using the init function, I was setting up the physicsbody in code, and setting the width slightly smaller than the squares width (that way when my hero slides off the square, there isn't a gap where the rounded corner is..

I know I can use the alpha mask physics body to get the same affect, except that with this, There seems to be a 1 px'ish gap when my hero is on the blocks, and it doesn't look good.

Wondering the reason why I can't set the physics body this, and also how I can do it or get around it?

Thanks for any help!!!

Update:

    required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    if let p = userData?.value(forKey: "col") as? String {
        setup(p)
        print("working")
    }
}
func setup(_ col: String) {
    setupPhysics()
    //allSprites.append(self)

In the setupPhysics I have:

override func setupPhysics() {
    physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: frame.width - 4, height: frame.height - 1))
...more code...
}

This is my code for the sprite, and I have it correctly setup in the sks file...

I commented out the append to allSprites, so that I can demonstrate that it doesn't work. With the append uncommented, the sprites get added to allSprites, and then in my didMove function in the Scene file, it loops through allSprites and runs the setupPhysics():

  func setup(_ col: String) {
    //setupPhysics()
    allSprites.append(self)

// scene file
    func setupAllSpritesPhysics() {
    for sprite in allSprites { sprite.setupPhysics() }
}

@Knight0fDragon :

You mention that this is an ugly fix. I disagree given the fact that it won't work the 'correct' way. And currently I don't have enough sprites to cause any kind of lag in the scene loading. I can look into that in the future if that is the case.

I'll admit I haven't tried the method you mentioned because I don't want to create a child node for each sprite I create in order to get around this even if it works. I appreciate the advice so far though.

1
it would help if you showed some more info. if the hero physics is setup in code show that code or show an image showing what is happening when the sprites interact. The more info you can provide the easier it is to figure out your issues.Ron Myschuk
Thanks for the comments, i don't have my computer in front of me at the moment but I will update the question when I get a chance. I can say, that the init function functions correctly and works, I only have 1 init function. THe function that sets up the physics is called after super.init is called. I did get it too work using a wait skaction with a completion closure... so I assume the super.init needs more time to finish, but that seems kind of hacky...Discoveringmypath
did you even check to see if that print line is happeningKnight0fDragon
also are you hitting the correct setup methodKnight0fDragon
yes of course on first question and yes it is correct setup functionDiscoveringmypath

1 Answers

6
votes

To make this work with the SKS file, I would add a child SKNode with the dimensions of the body you want, and then in the Custom class code, do

required init(coder aDecoder:NSCoder){
    super.init(coder:aDecoder)
    if let child = childNode(withName:"child"), let physicsBody = child.physicsBody{
       self.physicsBody = physicsBody
       child.removeFromParent()
    }
}

What we are doing here is transfering the physics body from the child to the parent, and then killing the child off. This allows our code to be a little more dynamic, and keeps design seperate from functionality.

Well, nice little bug from apple.

What is happening is physicsWorld doesn't exist during the time NSCoder happens, and instead of placing the physics body attached to the sprites body into the world when it does exist, it decides to cache the one located in the SKS file, and this is why it doesn't work.

So a very convenient way to get around this issue, is to implement a worldNode (It is good practice to do this anyway, especially if you want to create a pause screen) and just remove it then add it back in during sceneLoad:

class GameScene: SKScene,SKPhysicsContactDelegate {
    lazy var worldNode : SKNode = { self.childNode(withName:"//worldNode")!}()

    override func sceneDidLoad() {
        worldNode.removeFromParent()
        addChild(worldNode)
    }
}