在SpriteKit

时间:2017-01-30 18:41:08

标签: ios swift sprite-kit swift3 xcode8

以前我质疑是否可以使用场景编辑器创建复杂的SKSpriteNodes,而不是仅使用它来布局SKScenes。在@Anton Rogachevskyi the previous question的帮助下,我开始使用unarchiveNodeFromFile来定位.SKS文件。它按照我的预期加载sks文件,但是当我尝试将它添加到当前场景时,没有任何内容出现。如果我在addChild行中断并预览它在预览窗口中正确显示的对象,所以我知道它正在找到正确的文件。在sks文件中是一个自定义对话框类,并在"所需的init中设置断点?(编码器aDecoder:NSCoder)"我可以告诉自定义对象正在初始化。

dialog being created in the scene editor

在对话框类中我以编程方式向对象添加一个粉红色的框,以显示它确实到达了类的初始化

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

在场景中,这是我找到对象并尝试将其添加到场景中的方式,它出现在预览中但屏幕上没有显示任何内容

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

同样,我可以在预览窗口中看到它,但是当它被添加到场景中时没有任何内容。

在将其添加到场景之前,我是否必须处理已取消归档的对象或对其执行某些操作?

我将代码拉出来并将其放入具有相同结果的测试项目中。

我尝试将sks文件(作为节点)添加到场景中,没有运气,我尝试从sks文件中隔离出对话框并添加它没有运气

1 个答案:

答案 0 :(得分:2)

问题不在于是否将其作为未归档文件加载,或者是否将其加载为SKReferenceNode。虽然在找到并研究这个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 let teamDialog = dialogScene.childNode(withName: "//teamDialog") as? TeamDialog {
        teamDialog.setup(scene: self)
        teamDialog.position = CGPoint(x: 0, y: 0)
        dialogScene.zPosition = 5000
        addChild(dialogScene)
    }