Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
760 views
in Technique[技术] by (71.8m points)

ios - Unarchived Node doesn't appear when added to parent in SpriteKit

Previously I was questioning if i could use the Scene editor to create complex SKSpriteNodes vs just using it to layout SKScenes. With the help of @Anton Rogachevskyi the previous question I started using unarchiveNodeFromFile to locate the .SKS file. It loads the sks file as I would expect, but when I try to add it to the current scene nothing appears. If I break on the addChild line and preview the object it displays in the preview window properly, so I know it is finding the correct file. Inside the sks file is a custom dialog class and setting breakpoints in "required init?(coder aDecoder: NSCoder)" I can tell that the custom object is getting initialized properly.

dialog being created in the scene editor

inside the dialog class I programmatically add a pink box to the object to show that it does reach the init of the class

class TeamDialog: SKSpriteNode {

init(size: CGSize) {
    super.init(texture: nil, color: .red, size: size)
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)

    setup()
}

func setup() {

    let pinkBox = SKSpriteNode(color: .magenta, size: CGSize(width: 100, height: 100))
    pinkBox.zPosition = 500
    addChild(pinkBox)
}
}

And in the Scene this is how I find the object and try to add it to the scene, it appears in the preview but nothing shows up on the screen

private func displayDialog() {

    if let wtf = unarchiveNodeFromFile(file: "TeamDialog")! as SKNode? {

        let layer = SKSpriteNode(color: .clear, size: self.size)
        layer.zPosition = 5000
        layer.position = CGPoint(x: self.size.width / 2, y: self.size.height / 2)
        addChild(layer)

        for child in wtf.children {
            print("child (child.name)")
            if let teamDialog = child as? TeamDialog {
                teamDialog.removeFromParent()
                layer.zPosition = 1
                layer.addChild(teamDialog)
            } 
        }
    }
}

func unarchiveNodeFromFile(file: String) -> SKNode? {

    if let path = Bundle.main.path(forResource: file, ofType: "sks") {

        let fileData = NSData.init(contentsOfFile: path)
        let archiver = NSKeyedUnarchiver.init(forReadingWith: fileData as Data!)
        archiver.setClass(SKNode.classForKeyedUnarchiver(), forClassName: "SKScene")
        let node = archiver.decodeObject(forKey: NSKeyedArchiveRootObjectKey) as! SKNode
        archiver.finishDecoding()
        return node
    } else {
        return nil
    }
}

break preview of the object

Again, I can see it in the preview window but nothing appears when it is added to the scene.

Do I have to handle an object that has been unarchived differently or do something to it before I can add it to the scene?

I pulled the code out and have put it in a test project with the same results.

I've tried adding the sks file (as a node) to the scene with no luck, and i've tried isolating out the dialog from the sks file and adding it with no luck

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The problem wasn't whether or not Loaded it as an unarchived file or if I loaded it as a SKReferenceNode. Although after finding out about and researching this SKReferenceNode is EXACTLY the way to go and was probably made for this purpose.

The problem was that in the scene editor the custom object was positioned beside the scene (x = -1500) because when I originally constructed it was in the scene.sks file and I didn't want it on top of the scene objects. when I transferred it to it's own sks file it kept it's positioning. I didn't think that this was a big deal because after I loaded the sks file into a variable I set it's position to CGPoint(x: 0, y: 0) in code. The problem is that you CANNOT move the loaded scene object around the existing scene, so if it is off screen it will stay offscreen. Setting the position did nothing, and it didn't matter if it was an unarchived file or SKReferenceNode it wouldn't move.

So i referenced the first child in the sks file and set it's position and viola!

If anyone is interested at what can be done with this setup, you can create and layout complex custom objects in their own sks file and then load them into your scene file. The beauty of doing it this way is that your sks files don't become cluttered and then your custom object sks's can be reference in multiple different scenes.

    let path = Bundle.main.path(forResource: "TeamDialog", ofType: "sks")
    let dialogScene = SKReferenceNode (url: URL (fileURLWithPath: path!))
    if let teamDialog = dialogScene.childNode(withName: "//teamDialog") as? TeamDialog {
        teamDialog.setup(scene: self)
        teamDialog.position = CGPoint(x: 0, y: 0)
        dialogScene.zPosition = 5000
        addChild(dialogScene)
    }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...