SpriteKit, кнопка возврата в главное меню

У меня проблемы с реализацией кнопки, которая перенесет вас в главное меню из GameScene.

Это мой код GameScene:

let stoneLayer: SKNode = SKNode()
let cardLayer: SKNode = SKNode()
let menuPausaLayer: SKNode = SKNode()

class GameScene: SKScene {

override func didMoveToView(view: SKView) {
    /* Setup your scene here */
    backgroundColor = SKColor.blackColor()

    addChild(stoneLayer)
    addChild(cardLayer)
    addChild(menuPausaLayer)

    //Creazione posizioni carte
    for i in 0...15 {
        let cardLocation = SKSpriteNode(color: .orangeColor(), size: CGSize(width: cardWidth, height: cardHeight))
        cardLocation.position = CGPointMake(cardLocPosition[i].x, cardLocPosition[i].y)
        cardLocation.texture = SKTexture(imageNamed: "location")
        cardLocation.zPosition = -90
        addChild(cardLocation)
        //grid[i] = 0
    }

    //Pulsanti
    pauseButton.position = pauseButtonPosition
    addChild(pauseButton)


    loadDeck()

}

Когда я приостанавливаю игру, я добавляю exitButton в menuPausaLayer. Вот код, который я использую для этой кнопки:

let exitButton = button(buttonTexture: "pauseMenuButton", 
                        buttonWidth: menuPausaBottonWidth, 
                        buttonHeight: menuPausaBottonHeight, 
                        action: {exit()}
})

func exit() {
    print("Back to Main Menu")

    let newScene = MainMenuScene(size: UIScreen.mainScreen().bounds.size)
    newScene.scaleMode = .AspectFill
    scene?.view?.presentScene(newScene)   
}

Но не вышло ... Есть способ создать функцию смены сцены вне класса SKScene ?? Заранее спасибо :)

ОБНОВЛЕНИЕ: вот настраиваемый класс, который я использую для кнопки:

class button: SKSpriteNode {

//NSCoder non supportato
required init(coder aDecoder: NSCoder) {
    fatalError("NSCoding not supported")
}

var buttonTexture: SKTexture
var buttonWidth: CGFloat
var buttonHeight: CGFloat
var action: () -> Void

init(buttonTexture: String, buttonWidth: CGFloat, buttonHeight: CGFloat, action: () -> Void) {

    self.buttonTexture = SKTexture(imageNamed: buttonTexture)
    self.buttonWidth = buttonWidth
    self.buttonHeight = buttonWidth
    self.action = action

    super.init(texture: self.buttonTexture, color: .whiteColor(), size: CGSize(width: buttonWidth, height: buttonHeight))
    userInteractionEnabled = true
}

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    for _ in touches {

        let scale = SKAction.scaleTo(1.1, duration: 0.1)
        runAction(scale)
    }
}

override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
    for touch in touches {

        let location = touch.locationInNode(scene!)
        let touchedNode = nodeAtPoint(location)

        let scale = SKAction.scaleTo(1.0, duration: 0.1)
        runAction(scale)

        if touchedNode.containsPoint(location) {
           action()
        }

    }
}

person Fabio    schedule 02.08.2016    source источник
comment
Фабио, добро пожаловать в SO. Не могли бы вы лучше объяснить, что такое exitButton, это настраиваемый класс?   -  person Alessandro Ornano    schedule 02.08.2016
comment
Да, это кастомный класс.   -  person Fabio    schedule 02.08.2016
comment
Кажется, проблема связана с методами touchesBegan или touch regognize, не могли бы вы опубликовать еще код?   -  person Alessandro Ornano    schedule 02.08.2016
comment
Я добавил код в вопрос.   -  person Fabio    schedule 02.08.2016
comment
Я получаю следующую ошибку: использование неразрешенного идентификатора «сцена». Я думаю, это причина, по которой я объявляю функцию и кнопку вне класса SKScene.   -  person Fabio    schedule 02.08.2016
comment
Вы пытались получить сцену из if let parent = self.parent {}?   -  person Alessandro Ornano    schedule 02.08.2016
comment
Нет ... Я попробую! Спасибо ;)   -  person Fabio    schedule 02.08.2016


Ответы (3)


Как объяснили Apple документы, SKNode также имеет атрибут с именем parent, поэтому SKSpriteNode наследуется от SKNode, тогда в вашем class button: SKSpriteNode (который в вашем коде напрямую добавляется в сцену) вы можете:

if let parent = self.parent where parent is SKScene {
   let pScene = parent as! SKScene
   // do whatever you want with your scene
}
person Alessandro Ornano    schedule 02.08.2016
comment
Спасибо за помощь! Я вставил в функцию exit () следующий код: if let parent = exitButton.parent, где parent - SKScene {let scene = parent as! SKScene ... и т.д ... ...} и он работает правильно! - person Fabio; 03.08.2016
comment
Это совершенно неверно. Чтобы перейти к сцене из узла, вы используете свойство сцены узла, которое будет равно нулю, если узел не является частью сцены if let pScene = scene {... - person Daniel Kanaan; 03.08.2016
comment
Это правильно, узел - это кнопка, непосредственно добавленная в self.scene в соответствии с кодом OP, поэтому сцена является родительской, вы читали код OP? - person Alessandro Ornano; 03.08.2016

При использовании следующей функции все работает правильно! Спасибо!

func exit() {
print("Back to Main Menu")

if let parent = exitButton.parent where parent is SKScene {
    let parentScene = parent as! SKScene
    // do whatever you want with your scene
    print ("YES")

    let skView = parentScene.view! as SKView
    skView.showsFPS = true
    skView.showsNodeCount = true
    skView.multipleTouchEnabled = false

    /* Sprite Kit applies additional optimizations to improve rendering performance */
    skView.ignoresSiblingOrder = true

    /* Set the scale mode to scale to fit the window */
    let mainMenuScene = MainMenuScene(size: skView.bounds.size)
    mainMenuScene.scaleMode = .ResizeFill //.AspectFill

    skView.presentScene(mainMenuScene)

}
person Fabio    schedule 03.08.2016

Вам действительно не следует получать доступ к действиям, связанным с ViewController, из SKScene, а это именно то, что вы хотите сделать. Вместо этого в раскадровке должны быть действия, связанные с пользовательским интерфейсом.

Однако вы можете перейти к родительскому контроллеру представления из SKScene.

Используя этот пример, вы можете получить контроллер представления как следует:

extension UIView {
    var parentViewController: UIViewController? {
        var parentResponder: UIResponder? = self
        while parentResponder != nil {
            parentResponder = parentResponder!.nextResponder()
            //swift 3: parentResponder = parentResponder!.next()
            if let viewController = parentResponder as? UIViewController {
                return viewController
            }
        }
        return nil
    }
}

Затем в своей игровой сцене вы должны использовать

(view!.parentViewController as! GameViewController).dismiss(animated: true, completion: nil)

В одном узле вы должны использовать:

(scene!.view!.parentViewController as! GameViewController).dismiss(animated: true, completion: nil)

Или вы можете добавить настраиваемую функцию в свой контроллер представления, чтобы сделать это.

Код Swift 3 находится в комментариях выше

Опять же, не рекомендуется. Вы должны раскадровать свой пользовательский интерфейс и покинуть игровую сцену, чтобы начать игру. Контроллер навигации - идеальный способ сделать это.

person Daniel Kanaan    schedule 02.08.2016
comment
Прежде всего OP говорят о родительском узле SKNode, а не о SKScene. У вас также не может быть действий, связанных с пользовательским интерфейсом, в раскадровке с использованием SpriteKit, у вас не может быть непосредственно раскадровки, и все, что у вас есть, может работать лучше. Ваш пример связан с UIKit, ничего не касается этого вопроса. NavigationController для чего? Swift 3 ?? Вы можете лучше объяснить свой ответ? - person Alessandro Ornano; 02.08.2016
comment
Я обновился, чтобы переходить от узла к сцене. Это просто node.scene?. Вы абсолютно можете разместить элементы пользовательского интерфейса поверх сцены набора спрайтов. Вы должны включить в свою раскадровку представление для игры (класс SKView), а также любые другие элементы, которые вам нравятся НАД skview. Skview - это только ОДИН вид из многих в контроллере представления. Мой совет - создать другое представление и показывать его, когда оно вам нужно. Прозрачный? - person Daniel Kanaan; 03.08.2016
comment
У меня есть свои игры со времен первой версии спрайт-кита без раскадровки, я действительно не понимаю, о чем вы говорите. Зачем вам нужен еще один вид вместе с SKView, извините, но я могу продолжать не понимать .. - person Alessandro Ornano; 03.08.2016