Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SpriteKit: run action while scene is paused

I have a button to pause the game on my code. What I want is that pausing the game with that button makes a message that says "Paused" to appear. However, since the scene is paused, the message does not appear.

What I have right now is a SKLabelNode with the alpha on 0.0 at the beginning and when the user pauses the game, it changes to 1.0 with fadeInWithDuration(). Then when the user presses the button again, it changes back to 0.0 with fadeOutWithDuration(). The problem is that the SKAction with fadeInWithDuration() does not run when the scene is paused.

How could I achieve this?

like image 690
José María Avatar asked Feb 21 '16 13:02

José María


3 Answers

The best way, one Apple also uses in "DemoBots", is to create a world node that you pause instead of the scene.

Create a worldNode property

class GameScene: SKScene {

    let worldNode = SKNode()
}

add it to the scene in didMoveToView

addChild(worldNode)

and than add everything you need paused to the worldNode. This includes actions that are normally run by the scene (eg. timers, enemy spawning etc)

worldNode.addChild(someNode)
worldNode.run(someSKAction)

Than in your pause func you say

worldNode.isPaused = true
physicsWorld.speed = 0

and in resume

worldNode.isPaused = false
physicsWorld.speed = 1

You can also add an extra check in your Update function if you have stuff there that you want to ignore when paused.

override func update(_ currentTime: CFTimeInterval) {

    guard !worldNode.isPaused else { return }

    // your code
}

This way it's much easier to add your paused label or other UI when your game is paused because you haven't actually paused the scene. You can also run any action you want, unless that action is added to the worldNode or to a child of worldNode.

Hope this helps

like image 131
crashoverride777 Avatar answered Oct 21 '22 00:10

crashoverride777


Instead of pausing the scene, you could layer some nodes your scene like this

 SKScene
 |--SKNode 1
 |  |-- ... <--place all scene contents here
 |--SKNode 2
 |  |--  ... <--place all overlay contents here

Then when you want to pause the game, you pause only SKNode 1.

This allows node SKNode 2 to continue to run, so you can do things like have animations going, and have a button that unpauses the scene for you, without having the need to add some non Sprite Kit object into the mix.

like image 43
Knight0fDragon Avatar answered Oct 20 '22 23:10

Knight0fDragon


A quick workaround would be to pause your game after the SKLabelNode appears on screen:

let action = SKAction.fadeOutWithDuration(duration)
runAction(action) {
    // Pause your game
}

Another option would be to mix UIKit and SpriteKit and inform the ViewController back that it needs show this label.

class ViewController: UIViewController {
    var gameScene: GameScene!

    override func viewDidLoad() {
        super.viewDidLoad()
        gameScene = GameScene(...)
        gameScene.sceneDelegate = self
    }
}

extension ViewController: GameSceneDelegate {
    func gameWasPaused() {
        // Show your Label on top of your GameScene
    }
}

protocol GameSceneDelegate: class {
    func gameWasPaused()
}

class GameScene: SKScene {
    weak var sceneDelegate: GameSceneDelegate?

    func pauseGame() {
        // Pause
        // ...
        sceneDelegate?.gameWasPaused()
    }
}
like image 34
fdiaz Avatar answered Oct 20 '22 23:10

fdiaz