0

So for a school project, I have been tasked with making a 2D game. The game is fine but I'm struggling with how to make a back button (In the middle of the page) so was wondering if there was specific code to make this work. I am using spriteKit so I'm trying to go back to the previous scene after clicking on a colour sprite.

I apologise if this is a stupid question but I am slightly new to Swift.

Kind Regards, James

James
  • 49
  • 1
  • 10
  • 1
    How is the previous scene defined in your game view controller that display the SKView object? – El Tomato May 19 '17 at 21:49
  • [Transition using standard init(size:) initializer](http://stackoverflow.com/a/27935104/3402095), [Transition using fileNamed: convenience initializer](http://stackoverflow.com/a/37394430/3402095), [Detect which node is tapped](http://stackoverflow.com/a/41324936/3402095), [Custom button & delegation pattern](http://stackoverflow.com/a/36524132/3402095), and last but not least : [How to ask a good question on Stackoverflow](https://stackoverflow.com/help/how-to-ask). – Whirlwind May 19 '17 at 23:04

2 Answers2

1

Here is an example of how you can create a button using a colored sprite. It shows how you can set up a button to receive touch events and how you can use those touch events to navigate between scenes.

In this example you can navigate forward to new scenes and backwards to previous scenes.

import SpriteKit

class Button: SKSpriteNode {

    var tapped: (() -> Void)?

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        tapped?()
    }

}

class GameScene: SKScene {

    var parentScene: SKScene?
    var sceneCount = 1

    override func didMove(to view: SKView) {
        if parentScene != nil {
            let backButton = addButton(color: .red, position: CGPoint(x: -200, y: 0))
            backButton.tapped = {
                if let previousScene = self.parentScene {
                    view.presentScene(previousScene)
                }
            }
        }

        let nextButton = addButton(color: .blue, position: CGPoint(x: 200, y: 0))
        nextButton.tapped = {
            if let nextScene = SKScene(fileNamed: "GameScene") as? GameScene {
                nextScene.scaleMode = self.scaleMode
                nextScene.parentScene = self
                nextScene.sceneCount = self.sceneCount + 1
                view.presentScene(nextScene)
            }
        }

        let label = SKLabelNode(text: "Scene \(sceneCount)")
        addChild(label)
    }

    func addButton(color: SKColor = .white, position: CGPoint = .zero) -> Button {
        let button = Button(color: color, size: CGSize(width: 200, height: 200))
        button.position = position
        button.isUserInteractionEnabled = true
        addChild(button)
        return button
    }

}
mikeytdan
  • 254
  • 2
  • 8
0

Too add a button the simplest way is to detect touches on your sprite(s) in the relevant SKScene.

enum NodeName: String {
   case coloredSprite1
   case coloredSprite2
}

class GameScene: SKScene {

     let coloredSprite = SKSpriteNode(imageNamed: "YourImageName")

     /// Scene setup
     override func didMove(to view: SKView) {
       // set up your colored sprite if necessary
       // Give your sprites unique names to identify them

       coloredSprite.name = NodeName.coloredSprite1.rawValue // always use enums for things like string identifiers so you avoid typos
     }

     /// Touches
     override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
         for touch in touches {
             let location = touch.location(in: self)
             let touchedNode = atPoint(location)

             // Way 1 by node (probably less preferable)
             switch touchedNode {
             case coloredSprite:
                 // do something (e.g call loadScene method)
                // see below
             default: 
                 break
             }

             // Way 2 by node name (probably more preferable)
             // name is an optional so we have to unwrap it when using it in the switch statement. 
             // The easiest way is by providing an alternative string, by using the nil coalescing operator (?? "NoNodeNameFound")

             switch touchedNode.name ?? "NoNodeNameFound" {
             case NodeName.coloredSprite1.rawValue:
                // do something (e.g call loadScene method)
                // see below
             default: 
                break
             }
        }
    }

    // Also call touchesEnded, touchesMoved and touchesCancelled and do necessary stuff
}

For a more reusable solution you ideally want to create a button subclass. There is quite a few tutorials to google on how to do this.

To than transition between SKScenes you can create a loadScene method in each scene and than call them when necessary.

// Start Scene
class StartScene: SKScene {
   ...

   func loadGameScene() {

        // If you do everything in code
        let gameScene = GameScene(size: self.size)
        view?.presentScene(gameScene, transition: ...)

        // If you use SpriteKit scene editor
        guard let gameScene = SKScene(fileNamed: "GameScene") else { return } // fileNamed is the name you gave the .sks file
        view?.presentScene(gameScene, transition: ...)
   }
}

// Game scene
class GameScene: SKScene {
     ....

     func loadStartScene() {
        // If you do everything in code
        let startScene = StartScene(size: self.size)
        view?.presentScene(startScene, transition: ...)

        // If you use SpriteKit scene editor
        guard let startScene = SKScene(fileNamed: "StartScene") else { return } // fileNamed is the name you gave the .sks file
        view?.presentScene(startScene, transition: ...)
   }
}

Hope this helps

crashoverride777
  • 10,581
  • 2
  • 32
  • 56
  • I added some more detail to my answer with a simple example on how to do touches in SpriteKit. – crashoverride777 Jun 06 '17 at 13:14
  • Thank you again, the help is very much appreciated! – James Jun 10 '17 at 09:44
  • I am now in the process of making the game scene change back to the menu when a score counter gets to 10. Would It require the same or similar code or would doing that be completely different? – James Jun 10 '17 at 09:47
  • Same code basically. You would have some logic somewhere in your code that checks the score value everytime it increases. You can than check if it's 10, and if it is call the loadScene method. – crashoverride777 Jun 10 '17 at 09:49
  • No worries. If you get stuck just ask another question and I will try to help. – crashoverride777 Jun 10 '17 at 10:21