且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

在SpriteKit中添加到父级时,未显示未归档的节点

更新时间:2023-02-01 23:30:06

问题不在于是否将其作为未归档文件加载,或者我是否将其加载为SKRefere nceNode。虽然在找到并研究这个SKReferenceNode之后,确实可以采用这种方式,但可能就是出于此目的。



问题是在场景编辑器中自定义对象是位于场景旁边(x = -1500),因为当我最初构建它时,它位于scene.sks文件中,我不希望它在场景对象之上。当我将它转移到它自己的sks文件时,它保持了它的定位。我不认为这是一个大问题,因为在我将sks文件加载到变量中后,我在代码中将它的位置设置为CGPoint(x:0,y:0)。问题是您无法在现有场景周围移动加载的场景对象,因此如果它在屏幕外,它将保持在屏幕外。设置位置什么也没做,如果它是一个未归档的文件或SKReferenceNode它不会移动也没关系。



所以我引用了sks文件中的第一个孩子并设置了它的位置和中提琴!



如果有人是对这个设置可以做什么感兴趣,您可以在他们自己的sks文件中创建和布局复杂的自定义对象,然后将它们加载到场景文件中。这样做的好处是你的sks文件不会变得杂乱,然后你的自定义对象sks可以在多个不同的场景中被引用。

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


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.

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
    }
}

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

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