Fabio
Fabio

Reputation: 23

SpriteKit, Back to Main Menu Button

I'm having trouble with implementing a button that will take you to the main menu from the GameScene.

This is my GameScene code:

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()

}

When I pause the Game, I add the exitButton to the menuPausaLayer. Here the code i use for this button:

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)   
}

But it did not works... There is a way to create a function to change scene outside of the SKScene class?? Thanks in advance :)

UPDATE: Here the custom class i use for the button:

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()
        }

    }
}

Upvotes: 2

Views: 1073

Answers (3)

Alessandro Ornano
Alessandro Ornano

Reputation: 35402

As explained to the Apple documents, SKNode has also an attribute named parent so SKSpriteNode is inherited from SKNode then in your class button: SKSpriteNode (that in your code is directly added to the scene) you can do:

if let parent = self.parent where parent is SKScene {
   let pScene = parent as! SKScene
   // do whatever you want with your scene
}

Upvotes: 1

Daniel K
Daniel K

Reputation: 1129

You really should not be accessing ViewController related actions from an SKScene, which is what you want to do. Instead, you should have UI related actions in your storyboard.

However, you can get to the parent view controller from an SKScene.

Using This example you can get the view controller as follows:

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
    }
}

Then in your Game Scene you would use

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

In one node, you would use:

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

Or you could add a custom function to your view Controller to do the above.

Swift 3 code is in the comments above

Again, not recommended. You should storyboard your UI and leave the game scene to play the game. A navigation Controller is an ideal way to do that.

Upvotes: 0

Fabio
Fabio

Reputation: 23

Using the following function all works properly! Thanks!

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)

}

Upvotes: 0

Related Questions