Я пытаюсь представить меню с двумя кнопками в качестве начальной сцены: play, credits. При нажатии на play я хочу представить другую сцену меню с 4 кнопками: tutorial, easy, hard, back.
Стратегия состоит в том, чтобы просто создавать кнопки как объекты SKSpriteNode и обрабатывать щелчки в функции touchesBegan.

В моем файле menuScene.sks я правильно разместил и назвал свои узлы. Здесь вы можете проверить файл menuScene.swift, связанный с этой сценой:

import SpriteKit

class menuScene: SKScene {

var playButton:SKSpriteNode!
var creditsButton:SKSpriteNode!

override func didMove(to view: SKView) {
    playButton = self.childNode(withName: "playButton") as! SKSpriteNode
    creditsButton = self.childNode(withName: "creditsButton") as! SKSpriteNode
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    // transition is defined in Helper.swift
    let touch = touches.first

    if let location = touch?.location(in: self){

        let nodesArray = self.nodes(at: location)

        if nodesArray.first?.name == "playButton" {
            let nextScene = difScene(size: self.size)
            self.view?.presentScene(nextScene, transition: transition)
        } else if nodesArray.first?.name == "creditsButton" {
            let nextScene = creditsScene(size: self.size)
            self.view?.presentScene(nextScene, transition: transition)
        }
    }
  }
}

Когда я бегу, menuScene отображается без проблем. Однако когда я нажимаю кнопку play, я получаю сообщение об ошибке, и это из следующей сцены: difScene. Здесь вы можете найти difScene.swift:

import SpriteKit

class difScene: SKScene {

var tutButton:SKSpriteNode!
var easyButton:SKSpriteNode!
var hardButton:SKSpriteNode!
var backButton:SKSpriteNode!

override func didMove(to view: SKView) {
    tutButton = self.childNode(withName: "tutButton") as! SKSpriteNode // error
    easyButton = self.childNode(withName: "easyButton") as! SKSpriteNode
    hardButton = self.childNode(withName: "hardButton") as! SKSpriteNode
    backButton = self.childNode(withName: "backButton") as! SKSpriteNode
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    let transition = SKTransition.push(with: .down, duration: 0.2)
    let touch = touches.first

    if let location = touch?.location(in: self){

        let nodesArray = self.nodes(at: location)
        if nodesArray.first?.name == "tutButton" {

            let nextScene = GameScene(size: self.size)
            self.view?.presentScene(nextScene, transition: transition)
        }

        if nodesArray.first?.name == "easyButton" {
            let nextScene = difScene(size: self.size)
            self.view?.presentScene(nextScene, transition: transition)
        }

        if nodesArray.first?.name == "hardButton" {
            let nextScene = difScene(size: self.size)
            self.view?.presentScene(nextScene, transition: transition)
        }

        if nodesArray.first?.name == "backButton" {
            let nextScene = menuScene(size: self.size)
            self.view?.presentScene(nextScene, transition: transition)
        }
    }
  }
}

Если это может быть полезно, вот мой GameViewController.swift:

import UIKit
import SpriteKit
import GameplayKit

class GameViewController: UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()

    if let scene = GKScene(fileNamed: "menuScene") {

        // Get the SKScene from the loaded GKScene
        if let sceneNode = scene.rootNode as! menuScene? {

            // Set the scale mode to scale to fit the window
            sceneNode.scaleMode = .aspectFill

            // Present the scene
            if let view = self.view as! SKView? {
                view.presentScene(sceneNode)

                view.ignoresSiblingOrder = true

                view.showsFPS = false
                view.showsNodeCount = false
            }
        }
    }
}

override var shouldAutorotate: Bool {
    return true
}

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    if UIDevice.current.userInterfaceIdiom == .phone {
        return .allButUpsideDown
    } else {
        return .all
    }
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Release any cached data, images, etc that aren't in use.
}

override var prefersStatusBarHidden: Bool {
    return true
  }
}

Я получаю следующую ошибку:

Поток 1: Неустранимая ошибка: неожиданно обнаружен ноль при развертывании необязательного значения

Я знаю, что это не уникальная ошибка. У меня есть Google, я смотрел учебные пособия и пытался получить решение из других потоков StackOverflow, но не смог преодолеть это.

1
mert dökümcü 25 Ноя 2017 в 18:09

1 ответ

Лучший ответ

Ошибка в этой строке

tutButton = self.childNode(withName: "tutButton") as! SKSpriteNode // error

Поскольку дочернего узла с именем "tutButton" нет, принудительное приведение его к SKSpriteNode вызывает ошибку.

Когда нажата кнопка воспроизведения, вы вызываете этот код:

let nextScene = difScene(size: self.size)
self.view?.presentScene(nextScene, transition: transition)

Это инициализирует новый difScene и представляет его, который, в свою очередь, вызывает приведенную выше строку кода, которая дает сбой.

У вас есть соответствующий файл sks для difScene, куда вы добавляете четыре кнопки, на которые вы ссылаетесь в didMove?

Если это так, вам необходимо инициализировать difScene файлом sks, как вы это делали для сцены меню:

let scene = GKScene(fileNamed: "difScene")

Если нет, вам нужно будет создать эти четыре узла кнопок и программно добавить их в качестве дочерних элементов в вашу сцену.


Примечание. В Swift принято именовать типы, начинающиеся с заглавных букв. Ваш menuScene должен быть MenuScene, а ваш difScene должен быть DifScene. Это упростит другим чтение и понимание вашего кода.

1
nathangitter 25 Ноя 2017 в 15:19