SpriteKit: странный сбой при предварительной загрузке текстурных атласов
В настоящее время я работаю над игрой для iOS с использованием SpriteKit, и я столкнулся со странным сбоем при реализации предварительной загрузки атласов текстур. Вот краткий обзор того, что я получил до сих пор:
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 немного длинная, поскольку она инициализирует камеру, карту тайлов, элементы пользовательского интерфейса и некоторые ограничения. Тем не менее, это компилируется просто отлично. Но когда я запускаю игру, она сразу же вылетает со следующей фатальной ошибкой: "неожиданно найден ноль при развертывании необязательного значения". Как оказалось, этим необязательным значением является (случайным образом) либо self.tilemap, либо self.cam, и ошибка возникает в функции update() GameScene в одной из следующих строк (также случайным образом):
// here
var p = self.cam.position
// or here
self.tilemap.update(delta)
Отладчик говорит мне, что либо self.tilemap, либо self.cam - ноль. Но я не могу понять, почему это так. Мне кажется, что функция didMoveToView выполняется при представлении сцены, а затем внезапно на полпути вызывается функция обновления, когда self.tilemap или self.cam еще не инициализированы.
Когда я изменяю функцию viewDidLoad GameViewController на это:
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)
}
[...]
все работает отлично. Но это, очевидно, не решение, потому что я хочу предварительно загрузить все перед началом сцены. Также обратите внимание: я знаю, что предварительно загруженные атласы сразу удаляются из памяти, так как я не храню строгую ссылку на них. Во всяком случае, этот код действительно только для демонстрации и тестирования.
Итак, мой вопрос: кто-нибудь когда-либо имел подобную проблему или знает, что происходит с этой ошибкой? Я не могу понять, что я делаю неправильно. Буду признателен за любую оказанную помощь.
1 ответ
Вы создаете приложение, используя шаблон, оно создаст вид как SCNView
, это SCNView
столкнуться с желанием иметь на доске объявлений SKView
,
- удалять
SCNView
от вашей раскадровки SKView
недоступно как опция просмотра- Введите регулярный
UIView
к раскадровке - По классу свойств введите
SKView
, он будет принимать, даже если его нет в списке - Это исправит проблему при попытке создать
SKView
Смотрите прикрепить изображение.