使用SpriteKit .sks场景文件创建子类别SKNodes

时间:2014-08-04 16:25:30

标签: ios sprite-kit skspritenode sknode

(这适用于XCode 6和iOS 8 beta 4)

喜欢新的SceneKit编辑器。我成功地将.sks文件中的场景加载到自定义SKScene类中。但是,它内部的对象被实例化为默认类(SKNode,SKSpriteNode等),我不知道如何绑定它们以实例化为自定义子类。

目前,我正在通过创建自定义类并将sprite节点链接为属性来解决这个问题,这样就可以了。

4 个答案:

答案 0 :(得分:8)

目前你应该在添加到SpriteKit游戏模板的方法中按名称进行操作。他们在WWDC 2014的SpriteKit最佳实践视频中介绍了这个主题。它很容易被遗漏,因为视频中有很多内容。

这是方法。

+ (instancetype)unarchiveFromFile:(NSString *)file {
    /* Retrieve scene file path from the application bundle */
    NSString *nodePath = [[NSBundle mainBundle] pathForResource:file ofType:@"sks"];
    /* Unarchive the file to an SKScene object */
    NSData *data = [NSData dataWithContentsOfFile:nodePath
                                          options:NSDataReadingMappedIfSafe
                                            error:nil];
    NSKeyedUnarchiver *arch = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
    [arch setClass:self forClassName:@"SKScene"];
    SKScene *scene = [arch decodeObjectForKey:NSKeyedArchiveRootObjectKey];
    [arch finishDecoding];

    return scene;
}

它是SKScene上的一个类别,其中包含从mainBundle中的.sks文件加载时使用NSKeyedUnarchiver替换类的方法。在iOS中,他们将其添加到GameViewController.m文件中,在OS X中,他们将其添加到AppDelegate.m文件中。

在此处或您的个人SKNode子类中,您可以实现此目的。这就是他在帖子中所做的。这是由Apple提供的,并在WWDC视频中介绍。我想明年它会得到更好的处理。在此期间,文件中的一个错误请求SKNodes获取类似于场景编辑器的IBDesignable。 :)

答案 1 :(得分:4)

我写了一个小助手代表来处理这个问题:https://github.com/ice3-software/node-archive-delegate。它使用NSKeyedUnarchiverDelegate按名称为您的精灵子类化。

答案 2 :(得分:3)

我做了一个小技巧如何使用SceneKit编辑器,我会尝试使用它,但我不确定这会如何降低性能。我想使用场景编辑器制作复杂的SKNodes结构并将它们加载到当前场景中。它也可以帮助子类化节点。

我在场景编辑器中配置我的节点,将父节点设置为名为“base”的空节点,并创建了SKNode的子类。然后我创建了一个init方法,并在我需要的时候调用它:

// subclass code
class MyOwnSKNodeSubclass: SKNode {

let nodeLayer = SKNode()

   init(fromNode: SKNode){
       super.init()

       nodeLayer.addChild(fromNode.childNodeWithName("base").copy() as SKNode)
       addChild(nodeLayer)
   }
}



// scene code
if let myNode = SKNode.unarchiveNodeFromFile("MyScene")
{
   // you can use your subclass here
   let node = MyOwnSKNodeSubclass(fromNode: myNode)

   addChild(node)
}

我也使用了自己的SKNode扩展,但没有太大区别,但是:

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

    if let path = NSBundle.mainBundle().pathForResource(file, ofType: "sks") {
        var nodeData = NSData.dataWithContentsOfFile(path, options: .DataReadingMappedIfSafe, error: nil)
        var archiver = NSKeyedUnarchiver(forReadingWithData: nodeData)

        archiver.setClass(self.classForKeyedUnarchiver(), forClassName: "SKNode")
        let scene = archiver.decodeObjectForKey(NSKeyedArchiveRootObjectKey) as SKNode
        archiver.finishDecoding()
        return scene
    } else {
        return nil
    }
}

正如我所说,我不确定生产力,但我认为如果不经常使用它,它不会造成太大伤害。希望这有助于某人。

答案 3 :(得分:2)

是的,Apple应该让我们所有人都更容易,但就目前而言,这是满足我需求的最可行的解决方案:

避免继承

当然,这可能根本不可能,但在我的情况下,我想到的子类包含控制我在SKS文件中布局的图形的逻辑......声音非常接近到ViewController,不是吗?

我创建了一个OverlayController类,我用它初始化它:

self.childNodeWithName(Outlet.OverlayNode)!

所以现在,覆盖节点只是一个愚蠢的节点,控制器是完全成熟的子类,具有所有的好处。

但还有更多

只是把它扔进去使这笔交易更加甜蜜:

private extension SKNode {
    var progressBar: SKNode {
        return self.childNodeWithName("ProgressBar")!
    }
}

这是新控制器类文件中的私有扩展,因此我们可以轻松访问愚蠢的SKNode的子项。

痛点

一个令人遗憾的痛点是触控处理。将SKNode子类化为自定义触摸处理是很自然的,并且组合方法在这方面几乎没有做任何事情。我现在暂时转发场景中的触摸,但如果有更好的方法,我会发布更新。