Sprite moves two places after being paused and then unpaused
As the member above me said the player is not really moving 2 spaces.
Also you should maybe change your strategy when pausing your game, because pausing the scene.view makes it very hard to add SpriteKit elements afterwards.
I think a better way is to create a worldNode in your GameScene and add all the sprites that need to be paused to that worldNode. It basically gives you more flexibility pausing a node rather than the whole scene.
First create a world node property
let worldNode = SKNode()
and add it to the scene in ViewDidLoad
addChild(worldNode)
Than add all the sprites you need paused to the worldNode
worldNode.addChild(sprite1)
worldNode.addChild(sprite2)
...
Create a global enum for your game states
enum GameState {
case Playing
case Paused
case GameOver
static var current = GameState.Playing
}
Than make a pause and resume func in your game scene
func pause() {
GameState.current = .Paused
// show pause menu etc
}
func resume() {
GameState.current = .Playing
self.physicsWorld.speed = 1
worldNode.paused = false
}
And finally add the actual pause code to your updateMethod. This way it will not resume the game even if spriteKit itself tries to resume (e.g. reopened app, dismissed alert etc)
override func update(currentTime: CFTimeInterval) {
if GameState.current == .Paused {
self.physicsWorld.speed = 0
worldNode.paused = true
}
}
In regards to your tapGesture recogniser, in the method that gets called after a tap you can add this before the rest of the code
guard GameState.current != .Paused else { return }
....
Hope this helps
How to prevent run SKAction on paused scene (after unpaused), texture of node not change after pause/unpause scene
I put my controls on their own layer (SKNode) controlsLayer.addChild(pauseButton) and game objects on their own layer "gameLayer" then when I want to pause the game, I just pause the gameLayer (gameLayer.isPaused = true). This stops the game objects from moving, gives the appearance of being paused but still allows me to things like actions, add objects etc.
override func update(_ currentTime: TimeInterval) {
if !gameLayer.isPaused {
moveBackground()
}
}
Paused layer come unpause after start app from background
So this is what worked for me:
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var gameLayer = SKNode()
override func didMove(to view: SKView) {
NotificationCenter.default.addObserver(self,
selector: #selector(GameScene.pause),
name: .UIApplicationDidBecomeActive,
object: nil)
let moveUp = SKAction.moveBy(x: 0, y: 100, duration: 2)
let sequence = SKAction.sequence([moveUp, moveUp.reversed()])
let loop = SKAction.repeatForever(sequence)
let sprite = SKSpriteNode(color: .purple, size: CGSize(width: 100, height: 100))
addChild(gameLayer)
gameLayer.addChild(sprite)
sprite.run(loop)
}
func pause(){
gameLayer.speed = 0
}
override func willMove(from view: SKView) {
super.willMove(from: view)
NotificationCenter.default.removeObserver(self,
name: .UIApplicationDidBecomeActive,
object: nil)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
gameLayer.speed = gameLayer.speed == 0 ? 1 : 0
}
}
I haven't had time to test more, but I was expecting that something like this:
func pause(){
gameLayer.isPaused = true
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
gameLayer.isPaused = !gameLayer.isPaused
}
would work, but surprisingly it isn't (the node continued with moving after the pause()
method was executed). I don't really know if this is a bug or a feature :) but IMHO, I would say it is a bug. Anyways, you can achieve what you want using the speed property. Just copy and paste this code to see how it works.
cancelling a tap gesture recongiser
You can remove Gesture on Pause click using following:
self.view.removeGestureRecognizer(YOUR_GESTURE_RECOGNISER)
and add it again if resume game
iOS unpausing game after didBecomeActive
Now I have your source, I see your problem.
You need to preserve your pause state:
class GameScene : SKScene
{
...
override var paused: Bool
{
get{
return super.paused;
}
set{
let value = self.gameLayer.paused
super.paused = newValue;
self.gameLayer.paused = value;
}
}
}
For some reason, scene paused is deciding to unpause all nodes under it
Also, you should pause your game when you leave the app, not when you come back.
//Functions from AppDelegate
func registerAppTransitionObservers(){
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(GameScene.applicationWillResign), name: UIApplicationWillResignActiveNotification, object: nil)
}
func applicationWillResign(){
print("WillResignActive")
pauseState()
}
And you can get rid of that check paused variable, that is redundant bloat code.
Keeping the game paused after app become active?
I think a better way is instead of pausing the whole scene you could create a worldNode in your GameScene and add all the sprites that need to be paused to that worldNode. Its better because if you pause the scene you cannot add pause menu nodes or use touches began etc. It basically gives you more flexibility pausing a node rather than the whole scene.
First create the world node (make global property if needed)
let worldNode = SKNode()
addChild(worldNode)
Than add all the sprites you need paused to the worldNode
worldNode.addChild(sprite1)
worldNode.addChild(sprite2)
Create an enum for your different game states
enum GameState {
case Playing
case Paused
case GameOver
static var current = GameState.Playing
}
Than make a pause func in your game scene
func pause() {
GameState.current = .Paused
//self.physicsWorld.speed = 0 // in update
//worldNode.paused = true // in update
// show pause menu etc
}
And call it like you did above using NSNotification or even better using delegation.
I prefer this method way more than pausing the scene from the gameViewController and also pausing the whole scene.
Create a resume method
func resume() {
GameState.current = .Playing
self.physicsWorld.speed = 1
worldNode.paused = false
// remove pause menu etc
}
and finally add this to your update method
override func update(currentTime: CFTimeInterval) {
if GameState.current == .Paused {
self.physicsWorld.speed = 0
worldNode.paused = true
}
Spritekit sometimes tends to resume the game when the app becomes active again or when an alert such as for in app purchases is dismissed. To avoid this I always put the code to actually pause the game in the update method.
Hope this helps.
GameplayKit Not Pausing When Scene Is Paused
Agents will continue along their last known valid velocity if another goal isn't altering it. If you'd like the agents to stop you could try using GKGoal's goalToReachTargetSpeed:.
Related Topics
How to Mask a Square Image into an Image with Round Corners in iOS
Storing Images Locally on an iOS Device
"Untrusted App Developer" Message When Installing Enterprise iOS Application
How to Rotate Orientation Programmatically in Swift
iOS 6 Facebook Posting Procedure Ends Up with "Remote_App_Id Does Not Match Stored Id"
How to Get iOS Device MAC Address Programmatically
Storing Asynchronous Cloud Firestore Query Results in Swift
Tutorial on How to Drag and Drop Item from Uitableview to Uitableview
iPhone - Draw Transparent Rectangle on Uiview to Reveal View Beneath
Ios9 - This Application Is Modifying the Autolayout Engine from a Background Thread -- Where
iOS Enterprise Distribution Through Ota
View with Continuous Scroll; Both Horizontal and Vertical
Present and Dismiss Modal View Controller
Open Phone Settings Programmatically in iOS9
Setting Tableheaderview Height Dynamically
Uicollectionview Adding Image to a Cell
How to Put the Image on the Right Side of the Text in a Uibutton