(this is for XCode 6 and iOS 8 beta 4)
(这适用于XCode 6和iOS 8 beta 4)
Love the new SceneKit editor. I'm successfully loading the scene from .sks file into a custom SKScene class. However, objects inside it are instantiated as default classes (SKNode, SKSpriteNode, etc), and i'm not sure how to bind them to be instantiated as custom subclasses instead.
喜欢新的SceneKit编辑器。我成功地将.sks文件中的场景加载到自定义SKScene类中。但是,它内部的对象被实例化为默认类(SKNode,SKSpriteNode等),我不知道如何绑定它们以实例化为自定义子类。
Currently, I'm getting around that by creating custom classes and linking to sprite nodes as a property, and that works ok
目前,我通过创建自定义类并链接到精灵节点作为属性来解决这个问题,这是正常的
4 个解决方案
#1
4
I wrote a little helper delegate to deal with this: https://github.com/ice3-software/node-archive-delegate. It uses the NSKeyedUnarchiverDelegate
to subclass your sprites by name.
我写了一个小助手代表来处理这个问题:https://github.com/ice3-software/node-archive-delegate。它使用NSKeyedUnarchiverDelegate按名称对sprite进行子类化。
#2
8
Currently you are supposed to do it by name in the method added to the SpriteKit game templates. They cover this topic in the SpriteKit Best Practices video in WWDC 2014. It's easy to miss because the video has a lot in it.
目前你应该在添加到SpriteKit游戏模板的方法中按名称进行操作。他们在WWDC 2014的SpriteKit最佳实践视频中介绍了这个主题。很容易错过,因为视频中有很多内容。
Here is the method.
这是方法。
+ (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;
}
It's a category on SKScene
that includes a method to use NSKeyedUnarchiver
to substitute the Class when loaded from the .sks file in the mainBundle. In iOS they add it to the GameViewController.m
file and in OS X they add it to the AppDelegate.m
file.
它是SKScene上的一个类别,它包含一个方法,当从mainBundle中的.sks文件加载时,使用NSKeyedUnarchiver替换Class。在iOS中,他们将其添加到GameViewController.m文件中,在OS X中,他们将其添加到AppDelegate.m文件中。
In here or in your individual SKNode subclasses, you can implement this. This is what he did below in his post. This was provided by Apple and covered in the WWDC video. I guess next year it will get handled better. In the meantime file a bug requesting SKNodes get something like IBDesignable for Scene Editor. :)
在此处或您的个人SKNode子类中,您可以实现此目的。这就是他在帖子中所做的。这是由Apple提供的,并在WWDC视频中介绍。我猜明年它会得到更好的处理。在此期间,文件中的一个错误请求SKNodes获取类似于场景编辑器的IBDesignable。 :)
#3
3
I made a little trick how to use SceneKit editor, and I'll try to use it but I don't sure about how this can reduce performance. I want to use scene editor to made complex SKNodes structures and load them into the current scene. It also could help with subclassing nodes.
我做了一个小技巧如何使用SceneKit编辑器,我会尝试使用它但我不确定这会如何降低性能。我想使用场景编辑器制作复杂的SKNodes结构并将它们加载到当前场景中。它还可以帮助子类化节点。
I configure my node in scene editor, set the parent node as empty node called "base" and made an subclass of SKNode. Then I made an init method and call it when I need to in my scene:
我在场景编辑器中配置我的节点,将父节点设置为名为“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)
}
I also used my own SKNode extension, not a big difference but:
我也使用了自己的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
}
}
As I said, I don't sure about productivity, but I assume that it won't harm too much if not use this very often. Hope this helps somebody.
正如我所说,我不确定生产力,但我认为如果不经常使用它,它不会造成太大伤害。希望这有助于某人。
#4
2
Yes, Apple ought to make this easier for all of us, but for the time being, here is the most viable solution for my needs:
是的,Apple应该让我们所有人都更容易,但就目前而言,这是满足我需求的最可行的解决方案:
Avoid subclassing
Sure, that may not be at all possible, but in my case, the subclass I had in mind contains logic to control the graphics I laid out in the SKS file ... Sounds awfully close to ViewController, doesn't it?
当然,这可能根本不可能,但在我的情况下,我想到的子类包含控制我在SKS文件中布局的图形的逻辑......听起来非常接近ViewController,不是吗?
I created a OverlayController
class, and I initialize it with:
我创建了一个OverlayController类,并将其初始化为:
self.childNodeWithName(Outlet.OverlayNode)!
So now, overlay node is just a dumb node, and the controller is the full fledged subclass that has all the goodies.
所以现在,覆盖节点只是一个愚蠢的节点,控制器是完全成熟的子类,具有所有的好处。
But there is more
但还有更多
Just throwing this in to sweeten the deal:
只是把它扔进去使这笔交易更加甜蜜:
private extension SKNode {
var progressBar: SKNode {
return self.childNodeWithName("ProgressBar")!
}
}
This is a private extension inside the new controller class file, so we can painlessly access the children of the dumb SKNode
.
这是新控制器类文件中的私有扩展,因此我们可以轻松访问哑SKNode的子项。
Pain point
An admittedly painful point is touch handling. It's natural to subclass an SKNode to do custom touch handling, and the composition approach hardly does anything on that front. I'm forwarding touches from the scene for now, but would post updates if there is a better way.
一个令人遗憾的痛点是触摸处理。将SKNode子类化为自定义触摸处理是很自然的,并且组合方法在这方面几乎没有做任何事情。我现在要转发场景,但如果有更好的方法,我会发布更新。
#1
4
I wrote a little helper delegate to deal with this: https://github.com/ice3-software/node-archive-delegate. It uses the NSKeyedUnarchiverDelegate
to subclass your sprites by name.
我写了一个小助手代表来处理这个问题:https://github.com/ice3-software/node-archive-delegate。它使用NSKeyedUnarchiverDelegate按名称对sprite进行子类化。
#2
8
Currently you are supposed to do it by name in the method added to the SpriteKit game templates. They cover this topic in the SpriteKit Best Practices video in WWDC 2014. It's easy to miss because the video has a lot in it.
目前你应该在添加到SpriteKit游戏模板的方法中按名称进行操作。他们在WWDC 2014的SpriteKit最佳实践视频中介绍了这个主题。很容易错过,因为视频中有很多内容。
Here is the method.
这是方法。
+ (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;
}
It's a category on SKScene
that includes a method to use NSKeyedUnarchiver
to substitute the Class when loaded from the .sks file in the mainBundle. In iOS they add it to the GameViewController.m
file and in OS X they add it to the AppDelegate.m
file.
它是SKScene上的一个类别,它包含一个方法,当从mainBundle中的.sks文件加载时,使用NSKeyedUnarchiver替换Class。在iOS中,他们将其添加到GameViewController.m文件中,在OS X中,他们将其添加到AppDelegate.m文件中。
In here or in your individual SKNode subclasses, you can implement this. This is what he did below in his post. This was provided by Apple and covered in the WWDC video. I guess next year it will get handled better. In the meantime file a bug requesting SKNodes get something like IBDesignable for Scene Editor. :)
在此处或您的个人SKNode子类中,您可以实现此目的。这就是他在帖子中所做的。这是由Apple提供的,并在WWDC视频中介绍。我猜明年它会得到更好的处理。在此期间,文件中的一个错误请求SKNodes获取类似于场景编辑器的IBDesignable。 :)
#3
3
I made a little trick how to use SceneKit editor, and I'll try to use it but I don't sure about how this can reduce performance. I want to use scene editor to made complex SKNodes structures and load them into the current scene. It also could help with subclassing nodes.
我做了一个小技巧如何使用SceneKit编辑器,我会尝试使用它但我不确定这会如何降低性能。我想使用场景编辑器制作复杂的SKNodes结构并将它们加载到当前场景中。它还可以帮助子类化节点。
I configure my node in scene editor, set the parent node as empty node called "base" and made an subclass of SKNode. Then I made an init method and call it when I need to in my scene:
我在场景编辑器中配置我的节点,将父节点设置为名为“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)
}
I also used my own SKNode extension, not a big difference but:
我也使用了自己的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
}
}
As I said, I don't sure about productivity, but I assume that it won't harm too much if not use this very often. Hope this helps somebody.
正如我所说,我不确定生产力,但我认为如果不经常使用它,它不会造成太大伤害。希望这有助于某人。
#4
2
Yes, Apple ought to make this easier for all of us, but for the time being, here is the most viable solution for my needs:
是的,Apple应该让我们所有人都更容易,但就目前而言,这是满足我需求的最可行的解决方案:
Avoid subclassing
Sure, that may not be at all possible, but in my case, the subclass I had in mind contains logic to control the graphics I laid out in the SKS file ... Sounds awfully close to ViewController, doesn't it?
当然,这可能根本不可能,但在我的情况下,我想到的子类包含控制我在SKS文件中布局的图形的逻辑......听起来非常接近ViewController,不是吗?
I created a OverlayController
class, and I initialize it with:
我创建了一个OverlayController类,并将其初始化为:
self.childNodeWithName(Outlet.OverlayNode)!
So now, overlay node is just a dumb node, and the controller is the full fledged subclass that has all the goodies.
所以现在,覆盖节点只是一个愚蠢的节点,控制器是完全成熟的子类,具有所有的好处。
But there is more
但还有更多
Just throwing this in to sweeten the deal:
只是把它扔进去使这笔交易更加甜蜜:
private extension SKNode {
var progressBar: SKNode {
return self.childNodeWithName("ProgressBar")!
}
}
This is a private extension inside the new controller class file, so we can painlessly access the children of the dumb SKNode
.
这是新控制器类文件中的私有扩展,因此我们可以轻松访问哑SKNode的子项。
Pain point
An admittedly painful point is touch handling. It's natural to subclass an SKNode to do custom touch handling, and the composition approach hardly does anything on that front. I'm forwarding touches from the scene for now, but would post updates if there is a better way.
一个令人遗憾的痛点是触摸处理。将SKNode子类化为自定义触摸处理是很自然的,并且组合方法在这方面几乎没有做任何事情。我现在要转发场景,但如果有更好的方法,我会发布更新。