我目前正在使用SpriteKit开发iOS游戏,我在实现纹理地图集的预加载时遇到了一个奇怪的崩溃。以下是我到目前为止的简要概述:
GameViewController.swift
import UIKit
import SpriteKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Configure the view.
let skView = self.view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
skView.showsDrawCount = true
skView.showsPhysics = false
skView.ignoresSiblingOrder = true
skView.multipleTouchEnabled = true
// Setup scene
let scene = GameScene(size: skView.bounds.size)
scene.scaleMode = .ResizeFill
let MyAtlas1 = SKTextureAtlas(named: "MyAtlas1")
let MyAtlas2 = SKTextureAtlas(named: "MyAtlas2")
let MyAtlas3 = SKTextureAtlas(named: "MyAtlas3")
SKTextureAtlas.preloadTextureAtlases([MyAtlas1, MyAtlas2, MyAtlas3], withCompletionHandler:
{
print("Everything loaded!")
// Present scene
skView.presentScene(scene)
})
}
[...]
GameScene.swift
import SpriteKit
class GameScene: SKScene {
var cam: SKCameraNode!
var tilemap: Tilemap!
var previousTime: CFTimeInterval = 0
[...]
override func didMoveToView(view: SKView) {
/* Setup your scene here */
[...]
// Setup camera
self.cam = SKCameraNode()
self.cam.setScale(self.camScaleFactor)
self.camera = self.cam
self.addChild(self.cam)
[...]
// Load Tilemap
self.tilemap = Tilemap(mapName: "testlevel2")
self.addChild(self.tilemap)
// Setup UI
[...]
}
[...]
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
if self.previousTime == 0 {
self.previousTime = currentTime
}
let delta = currentTime - self.previousTime
var p = self.cam.position
p.x += 2.0 * CGFloat(delta)
p.y += 1.5 * CGFloat(delta)
self.cam.position = p
// Update tilemap
self.tilemap.update(delta)
self.previousTime = currentTime
}
}
didMoveToView函数有点冗长,因为它初始化了一个摄像头,一个tilemap,UI的东西和一些约束。但是,编译得很好。但是当我运行游戏时,它会立即崩溃并出现以下致命错误:"在解开一个Optional值时意外发现nil"。事实证明,可选值是(随机)self.tilemap或self.cam,并且错误发生在GameScene的update()函数中的以下行之一(也是随机的):
// here
var p = self.cam.position
// or here
self.tilemap.update(delta)
调试器告诉我self.tilemap或self.cam是nil。但我无法弄清楚为什么会这样。在我看来,函数didMoveToView在场景出现时执行,然后突然中途执行,调用更新函数,其中self.tilemap或self.cam仍然未初始化。
当我将GameViewController的viewDidLoad函数更改为:
override func viewDidLoad() {
super.viewDidLoad()
// Configure the view.
let skView = self.view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
skView.showsDrawCount = true
skView.showsPhysics = false
skView.ignoresSiblingOrder = true
skView.multipleTouchEnabled = true
// Setup scene
let scene = GameScene(size: skView.bounds.size)
scene.scaleMode = .ResizeFill
let MyAtlas1 = SKTextureAtlas(named: "MyAtlas1")
let MyAtlas2 = SKTextureAtlas(named: "MyAtlas2")
let MyAtlas3 = SKTextureAtlas(named: "MyAtlas3")
SKTextureAtlas.preloadTextureAtlases([MyAtlas1, MyAtlas2, MyAtlas3], withCompletionHandler:
{
print("Everything loaded!")
})
// Present scene
skView.presentScene(scene)
}
[...]
一切都很完美。但这显然不是解决方案,因为我想在启动场景之前预先加载所有内容。还要注意:我知道预加载的地图集会立即从内存中删除,因为我没有对它们进行强有力的引用。无论如何,该代码实际上仅用于演示和测试。
所以我的问题是:有没有人遇到类似的问题或知道该错误发生了什么?我无法弄清楚我做错了什么。非常感谢任何帮助。