Swift SCNScene亚类化困难
我一直在尝试将SCNScene子类化,因为这似乎是保存场景相关逻辑的最佳位置。现在我不确定这是否会被提出,所以我的第一个问题是——我是否应该将SCNScene子类化,如果不是,为什么不?文档似乎表明它很常见,但我在网上看到的评论表明我不应该将其子类化。废话,我正在看Swift SCNScene亚类化困难,swift,scenekit,Swift,Scenekit,我一直在尝试将SCNScene子类化,因为这似乎是保存场景相关逻辑的最佳位置。现在我不确定这是否会被提出,所以我的第一个问题是——我是否应该将SCNScene子类化,如果不是,为什么不?文档似乎表明它很常见,但我在网上看到的评论表明我不应该将其子类化。废话,我正在看SKScene的文档。SCNScene类引用没有提到子类化 假设这样设计我的游戏是可以的,下面是我的进展 // GameScene.swift import Foundation import SceneKit class G
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
,与
在我的视图控制器中,我正试图像这样使用游戏场景
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()
}
}
但是,调用GameSecene.someMethod()
会触发EXEC\u BAD\u ACCESS
错误
另外,如果我省略了对GameSecene.someMethod
的调用,场景将正确加载,但是GameSecene
中被重写的初始值设定项似乎没有被调用
我不知道这里发生了什么。很明显,Swift中的子类化有一些我不理解的地方。或者,也许有些事情的运行顺序是我错过的
我应该子类化SCNScene
,如果不是,为什么不
不,您不需要子类化,而且您最好不要子类化SCNScene
更像基本数据/模型类(NSString
,UIImage
,等等),而不像行为/控制器/视图类(UIViewController
,UIControl
,等等)。也就是说,它是对某物(在本例中为3D场景)的一般描述或容器,并不真正提供行为。因为没有太多的行为方式,所以没有太多机会用子类重写行为。(类也不是围绕要重写的子类入口点设计的,比如viewDidLoad
等等。)
虽然可以将SCNScene
子类化,但这样做并不会带来太多好处,而且某些API可能无法按预期工作
但是,调用GameSecene.someMethod()
会触发EXEC\u BAD\u ACCESS
错误
另外,如果我省略了对GameSecene.someMethod
的调用,场景将正确加载,但是GameSecene
中被重写的初始值设定项似乎没有被调用
.scn
文件实际上是一个NSKeyedArchiver
归档文件,这意味着其中的对象具有与创建该文件相同的类。当您在SCNScene
子类上调用init(命名:)
时,超类的实现最终会调用NSKeyedUnarchiver
unarchiveObjectWithData:
以加载存档。如果没有一些未归档的损坏,该方法将实例化一个SCNScene
,而不是子类的实例
因为您没有获得子类的实例,所以不会调用子类初始值设定项,并且尝试调用子类的方法会导致运行时错误
旁白:为什么SpriteKit和SceneKit在这里不同SKScene
有点奇怪,因为它既不是纯模型类,也不是纯控制器类。这就是为什么您会看到很多项目,包括使用SKScene
子类的Xcode模板。然而,这种方法也有缺点——如果你不仔细计划,游戏逻辑很容易与游戏数据紧密结合,这使得扩展游戏(比如说,扩展到多个级别)需要繁琐的编码而不是数据编辑。有一部电影很值得一看
那么,该怎么办?
你在这里有几个选择
游戏对象。(如果您的游戏逻辑在多个场景之间转换或操纵多个场景的内容,这一点尤其有意义。)
SCNScene
中的内容放入子类的实例中-实例化子类,加载SCNScene
,然后将其根节点的所有子节点移动到子类的根节点中
nskeyedunachiver
加载子类,而不是SCNScene
。(您可以使用以下选项执行此操作。)
其中#1可能是最好的;dr:Extend
SCNNode
以编程方式生成场景
这一开始是对Rickster极好的回答的评论,但我觉得它太长了。本季度我教了一门课程,花了大量时间在SceneKit上。我们一直子类化SCNScene
,没有遇到任何问题
然而,在花了一个小时回顾了我展示的代码、学生们编写的代码以及大量其他示例代码(来自苹果和其他开发人员)之后,我不会再将SCNScene
子类化
没有一个Apple示例代码子类SCNScene
。这应该是一个非常有力的线索。处理序列化(initWithCoder
和从文件读取)是StackOverflow上经常出现的问题。这是你不想去那里的第二个强有力的线索
在我回顾的所有子类SCNScene
的代码中,这样做的原因是以编程方式生成场景。这是里克斯特的选择。但是这些代码实际上都不需要在SCNScene
上。如果您正在以特定配置构建一组节点,添加照明和查看约束,并设置材质,则感觉就像在构建一个SCNScene
。但实际上,您正在构建一个包含SCNNode
实例的树
因此,我认为事后看来,选择2并不能提供