Pause an Skaction in Spritekit with Swift

Pause an SKAction in Spritekit with Swift

You should run an action with key:

 square.runAction(SKAction.repeatActionForever(moveSequence), withKey:"moving")

Then, use action's speed property to pause it:

if let action = square.actionForKey("moving") {

action.speed = 0
}

or to unpause it:

action.speed = 1

Swift 3: Making a Pause Menu in SpriteKit by overlaying a SKView?

I struggled with the problem of pausing the game within the game scene for a while.

As several others have suggested in the comments, building a "pause scene" to transition into when the game is paused and then out of is an effective solution. This approach avoids problems you might run into with timers firing within the game scene while the game is paused or animation skips when waking up.

To implement a pause scene, I use a custom subclass of UIViewController to handle scene transitions.

Within my CustomViewController:

var sceneForGame: MyGameScene? //scene to handle gameplay
var paused: PauseScene? //scene to appear when paused

...

// presentPauseScene() and unpauseGame() handle the transition from game to pause and back

func presentPauseScene() {
//transition the outgoing scene
let transitionFadeLength = 0.30
let transitionFadeColor = UIColor.white
let pauseTransition = SKTransition.fade(with: transitionFadeColor, duration: transitionFadeLength)
pauseTransition.pausesOutgoingScene = true

let currentSKView = view as! SKView
currentSKView.presentScene(paused!, transition: pauseTransition)
}

func unpauseGame() {
let transitionFadeLength = 0.30
let transitionFadeColor = UIColor.white
let unpauseTransition = SKTransition.fade(with: transitionFadeColor, duration: transitionFadeLength)
unpauseTransition.pausesIncomingScene = false

let currentSKView = view as! SKView
currentSKView.presentScene(sceneForGame!, transition: unpauseTransition)
}

Within MyGameScene class (subclass of SKScene):

var parentViewController: CustomViewController?  // ref to the managing view controller 

...

// invoke this func when you want to pause
func setScenePause() {
parentViewController?.presentPauseScene()
self.isPaused = true
}

...

// you may need a snippet like this in your game scene's didMove(toView: ) to wake up when you come back to the game
else if self.isPaused {
self.isPaused = false
}

This is my PauseScene implementation. This version will unpause when the user taps anywhere in the pause scene, except for an endGameButton, which terminates the current game:

struct PauseNames {
static let endGameButton = "ENDGAME"
static let pausedButton = "PAUSE"
}

class PauseScene: SKScene {

var center : CGPoint?
var pauseButton: SKSpriteNode?
var endGameButton: SKSpriteNode?
var parentViewController: CustomViewController?

override func didMove(to view: SKView) {
setUpScene()
}

func setUpScene() {
self.backgroundColor = SKColor.white
self.center = CGPoint(x: self.size.width / 2, y: self.size.height / 2)
self.isUserInteractionEnabled = false

setUpSceneNodes()
showPauseEndButtons()

} // end setup scene

func setUpSceneNodes() {
let buttonScale: CGFloat = 0.5
let smallButtonScale: CGFloat = 0.25

let pauseOffset = //some CGPoint
let endGameOffset = //some CGPoint
pauseButton = SKSpriteNode(imageNamed: PauseNames.pausedButton)
pauseButton?.name = PauseNames.pausedButton
pauseButton?.anchorPoint = CGPoint(x: 0.5, y: 0.5)
pauseButton?.position = self.center! + pauseOffset
pauseButton?.alpha = 0
pauseButton?.setScale(buttonScale)

endGameButton = SKSpriteNode(imageNamed: PauseNames.endGameButton)
endGameButton?.name = PauseNames.pausedButton
endGameButton?.anchorPoint = CGPoint(x: 0.5, y: 0.5)
endGameButton?.position = self.center! + endGameOffset
endGameButton?.alpha = 0
endGameButton?.setScale(smallButtonScale)
}

func showPauseEndButtons() {
let buttonFadeInTime = 0.25
let pauseDelay = 1.0

self.addChild(pauseButton!)
self.addChild(endGameButton!)

pauseButton?.run(SKAction.fadeIn(withDuration: buttonFadeInTime))
endGameButton?.run(SKAction.fadeIn(withDuration: buttonFadeInTime))
self.run(SKAction.sequence([
SKAction.wait(forDuration: pauseDelay),
SKAction.run{ self.isUserInteractionEnabled = true }]))
}

func endGamePressed() {
// add confrim logic
parentViewController?.endGame()
}

func unpausePress() {
parentViewController?.unpauseGame()
}

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

if endGameButton!.contains(touchLocation) {
endGamePressed()
return
}
else {
unpausePress()
}

} // end for each touch
} // end touchesBegan

override func update(_ currentTime: TimeInterval) {
/* Called before each frame is rendered */
}

} //end class PauseScene

(The pauseButton is really more of a banner to inform the user of the pause state in this version)

SpriteKit pause Scene (Swift4.2)

I changed:

func pause(isPaused: Bool) {
let pauseAction = SKAction.run {
self.view?.isPaused = isPaused
}
self.run(pauseAction)
}

to:

func pause(isPaused: Bool) {
self.view?.isPaused = isPaused
}

it wokes without an action.

SpriteKit: run action while scene is paused

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

Stopping an running SKAction - Sprite Kit

You just have to use either:

  1. something.paused = false // or true to pause actions on the node
  2. something.removeAllActions() to definitely remove actions associated to the node
  3. name your action when launching something.runAction(action,withKey:"action1") and then something.removeActionForKey("action1") to remove a given action

You may also change the speed if needed.

Stopping/Pausing a sound that is set to repeat forever in SpriteKit Swift 3

Always good practice to show some code on stack overflow, with your current question we can only take guesses.

If you are using SKActions for sound you can give the repeat action a key and remove that action later. Create the key like so

 class GameScene: SKScene {

let soundKey = "RemoveSoundKey" // this avoids typos
}

and than change your action to this

 let repeatAction = SKAction.repeatActionForever(YOURSOUNDACTION)
run(repeatAction, withKey: soundKey)

Than you can say

 removeAction(forKey: soundKey)

when you want to stop the repeat action.

Note: If you run the action on a node e.g

 player.run(repeatAction...)

dont forget to call the remove action on the node

 player.removeAction(forKey: soundKey)

Hope this helps

How to use/implement pause() to pause a SKAudioNode?

SKAudioNodes are SKNodes and so are able to run any SKAction. So get a pause action and ask the node to run it (in Swift):

let audio : SKAudioNode
...
let pause = SKAction.pause()
audio.run(pause)

or shorter:

audio.run(SKAction.pause())

SKAction resumes when appDidBecomeActive() even when game is paused before appDidResignActive()

Change pauseGame() and resumeGame() methods to look like this:

private func pauseGame() {

node.speed = 0.0
gameState = .paused
pauseLayer.run(SKAction.fadeAlpha(to: 0.5, duration: 1))


}
private func resumeGame() {
pauseLayer.run(.fadeOut(withDuration: 1))
node.speed = 1.0
gameState = .inProgress
}

Note that I am using speed property instead of isPaused property... That is all the difference you need to make. Can't really say why this happens because this behaviour is not documented, but I have seen it already, and been writing about it probably more in detail in some of my previous posts.

Pause all ongoing asyncAfter() delays in SpriteKit game

If you're inside of a SKScene class just have the scene run a delay in the form of an SKAction. The action will pause and resume when you pause/unpause either the view or scene.

func spawnMeteorite(timeInterval:Double) {

run(SKAction.wait(forDuration: timeInterval), completion: {
self.spawnMeteorite(timeInterval: timeInterval * 0.9)
})

print("Spawn Meteorite")
}


Related Topics



Leave a reply



Submit