SpriteKit Project — AbsolutelyBrickingIt — Part 5: Navigate to the game scene
In this article, we’ll build on the simple menu screen with a basic animation and navigation to the game scene.
Animating the logo
Currently, the code to add the menu logo to the scene looks like:
let logoNode = SKSpriteNode(imageNamed: "logo")
logoNode.position = CGPoint(x: 0.5 * size.width, y: 0.8 * size.height)
addChild(logoNode)
Let’s update this to start at a lower y
value and to animate to the above y
value, using SKAction
's move(to: _, duration: _)
method:
let logoNode = SKSpriteNode(imageNamed: "logo")
logoNode.position = CGPoint(x: 0.5 * size.width, y: 0.5 * size.height)
addChild(logoNode)
logoNode.run(.move(to: CGPoint(x: 0.5 * size.width, y: 0.8 * size.height), duration: 1.0))
Running in the simulator now will show the logo moving from the center to the top of the screen when the menu scene is shown:
Detecting when play is touched
In order to detect when a node, such as the play node is touched, we need to keep a reference to the node we’re interested in and we need to compare it against touches on the screen:
class MenuScene: SKScene {
private var playNode: SKSpriteNode?
override func didMove(to view: SKView) {
...
addChild(playNode)
self.playNode = playNode
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let point = touch.location(in: self)
if playNode?.contains(point) == true {
print("Play touched")
}
}
}
}
Now we can see the resulting output in the console when clicking Play
in the Simulator:
Opening the game scene when play is touched
We’ll use the coordinator pattern to route the play button touch back to the GameViewController
and then present the GameScene
from there:
protocol MenuSceneCoordinator: AnyObject {
func menuScenePlayTapped(_ menuScene: MenuScene)
}
class MenuScene: SKScene {
weak var coordinator: MenuSceneCoordinator?
...
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let point = touch.location(in: self)
if playNode?.contains(point) == true {
coordinator?.menuScenePlayTapped(self)
}
}
}
}
If we run the app at this point, we’ll find that the console output is gone when we tap play. Nothing happens because we have yet to set the coordinator to handle the tap:
We can make the GameViewController
the coordinator for the MenuScene
to allow it to handle play taps:
class GameViewController: UIViewController {
override func viewDidLoad() {
...
let scene = MenuScene(size: CGSize(width: 375.0, height: 667.0))
scene.coordinator = self
...
}
...
}
extension GameViewController: MenuSceneCoordinator {
func menuScenePlayTapped(_ menuScene: MenuScene) {
print("Play tapped!")
}
}
Now when we tap play, we once again see message in the console. This time, however, the tap has been handled by a coordinator (i.e. the GameViewController
):
Finally, we can update the GameViewController
to present the GameScene
when a play tap occurs:
extension GameViewController: MenuSceneCoordinator {
func menuScenePlayTapped(_ menuScene: MenuScene) {
guard let view = self.view as? SKView else { return }
let scene = GameScene(size: CGSize(width: 375.0, height: 667.0))
scene.scaleMode = .resizeFill
view.presentScene(scene)
}
}
Run the app in the Simulator and confirm that the play button now leads to the game scene:
Code
This article corresponds to the merge commit Navigate to game scene (#5)
in the GitHub repository AbsolutelyBrickingIt