我一直在尝试将SCNScene子类化,因为这似乎是保持场景相关逻辑的最佳位置.现在我不确定是否已经推荐了所以我的第一个问题是 - 我是否应该继承SCNScene,如果不是为什么不呢?文档似乎表明它很常见,但我在线阅读的评论表明我不应该将其子类化.废话,我正在查看文档SKScene
.在SCNScene
类引用只字不提子类.
假设以这种方式构建我的游戏是可以的,这是我的进步
// GameScene.swift import Foundation import SceneKit class GameScene: SCNScene { lazy var enityManager: BREntityManager = { return BREntityManager(scene: self) }() override init() { print("GameScene init") super.init() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } func someMethod() { // Here's where I plan to setup the GameplayKit stuff // for the scene print("someMethod called") } }
注意:我正在lazy var
按照这个问题的答案使用
在我的视图控制器中,我试图像这样使用GameScene
class GameViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // create a new scene let scene = GameScene(named: "art.scnassets/game.scn")! // retrieve the SCNView let scnView = self.view as! SCNView // set the scene to the view scnView.scene = scene // Should print "someMethod called" scene.someMethod() } }
但是,调用会GameScene.someMethod()
触发EXEC_BAD_ACCESS
错误.
此外,如果我省略了调用GameScene.someMethod
,则场景正确加载,但是被覆盖的初始化器GameScene
似乎没有被调用.
我不确定这里发生了什么.很明显,在Swift中有一些关于子类化的东西我还没有理解.或者也许是某些方面的事情意味着我错过了.
我应该是子类
SCNScene
,如果不是,为什么不呢?
不,你不需要子类,你可能最好不要继承子类.SCNScene
更像基本数据/模型类(NSString
,UIImage
等)大于样行为/控制器/视图类(UIViewController
,UIControl
等).也就是说,它是某种东西的一般描述或容器(在这种情况下,是3D场景),并不真正提供行为.由于行为方式不多,因此没有太多机会用子类覆盖行为.(也不是围绕子类入口点设计的类意图被覆盖,比如viewDidLoad
和诸如此类的东西.)
虽然可以进行子类化SCNScene
,但这样做并没有获得太多收益,而且某些API可能无法按预期工作......
但是,调用会
GameScene.someMethod()
触发EXEC_BAD_ACCESS
错误.此外,如果我省略了调用
GameScene.someMethod
,则场景正确加载,但是被覆盖的初始化器GameScene
似乎没有被调用.
一个.scn
文件实际上是一个NSKeyedArchiver
存档,这意味着它里面的物品有被用来创建相同的类.当你调用init(named:)
你的SCNScene
子类,父类的实现,最终调用,直至NSKeyedUnarchiver
unarchiveObjectWithData:
加载存档.如果没有一些unarchiver修改,那么该方法将实例化一个SCNScene
,而不是你的子类的实例.
因为您没有获得子类的实例,所以不调用子类初始值设定项,并且尝试调用子类的方法会导致运行时错误.
旁白:为什么SpriteKit与SceneKit不同?SKScene
有点奇怪的是,它既不是纯粹的模型类,也不是纯粹的控制器类.这就是为什么你会看到很多项目,包括使用SKScene
子类的Xcode模板.然而,这种方法有一些缺点 - 如果你不仔细计划,你的游戏逻辑很容易与你的游戏数据紧密结合,这使得扩展你的游戏(比如说,到多个级别)需要繁琐的编码而不是数据编辑.有一个关于这个主题的WWDC 2014会议非常值得关注.
你有几个选择......
不要子类.将您的游戏逻辑保持在一个单独的类中.这不一定是视图控制器类 - 您可以拥有Game
视图控制器或应用程序委托所拥有的一个或多个对象.(如果您的游戏逻辑在多个场景的内容之间转换或操纵多个场景的内容,这尤其有意义.)
子类,但安排将未归档的东西SCNScene
放入子类的实例中 - 实例化您的子类,加载一个SCNScene
,然后将其根节点的所有子节点移动到子类的根节点中.
子类,但强制NSKeyedUnarchiver
加载您的子类而不是SCNScene
.(您可以使用类名映射执行此操作.)
其中,#1可能是最好的.