How to pause and restart NSTimer.scheduledTimerWithTimeInterval in spritekit [SWIFT] when home button is pressed?
You can use NSNotificationCenter
for that will fire a notification when you app enter into background or foreground as shown into below code:
var testEnemy : NSTimer?
override func didMoveToView(view: SKView) {
/* Setup your scene here */
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("appEnterIntoBackGround:"), name:UIApplicationDidEnterBackgroundNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("appBecomeActive:"), name:UIApplicationWillEnterForegroundNotification, object: nil)
testEnemy = NSTimer.scheduledTimerWithTimeInterval(1.2,
target: self,
selector: "timerUpdate",
userInfo: nil,
repeats: true)
}
And below is the helper methods:
func timerUpdate() {
print("called")
}
func appEnterIntoBackGround(notification : NSNotification) {
print("App is in Background")
testEnemy!.invalidate() //remove timer here when add enter into background.
}
func appBecomeActive(notification : NSNotification) {
print("App is active now")
//add your timer again when app enter into foreground
testEnemy = NSTimer.scheduledTimerWithTimeInterval(1.2,target: self,selector: "timerUpdate",userInfo: nil,repeats: true)
}
Pause NSTimer on home-button-press and start them again once the app is in foreground
Pausing of NSTimer
is not a native feature in objective-c or swift. To combat this, you need to create an extension, which I happen to have created and will share for you. This will work for both OS X and iOS
import Foundation
import ObjectiveC
#if os(iOS)
import UIKit
#else
import AppKit
#endif
private var pauseStartKey:UInt8 = 0;
private var previousFireDateKey:UInt8 = 0;
extension NSTimer
{
private var pauseStart: NSDate!{
get{
return objc_getAssociatedObject(self, &pauseStartKey) as? NSDate;
}
set(newValue)
{
objc_setAssociatedObject(self, &pauseStartKey,newValue,objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN);
}
}
private var previousFireDate: NSDate!{
get{
return objc_getAssociatedObject(self, &previousFireDateKey) as? NSDate;
}
set(newValue)
{
objc_setAssociatedObject(self, &previousFireDateKey,newValue,objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN);
}
}
func pause()
{
pauseStart = NSDate();
previousFireDate = self.fireDate;
self.fireDate = NSDate.distantFuture() ;
}
func resume()
{
if(pauseStart != nil)
{
let pauseTime = -1 * pauseStart.timeIntervalSinceNow;
let date = NSDate(timeInterval:pauseTime, sinceDate:previousFireDate );
self.fireDate = date;
}
}
}
Then when you need to use it, simply call timer.pause()
and timer.resume()
You of course have to keep track of your timers in your gamescene object to do this, so make sure that timer
is a variable accessible for the entire class, and when making your timer, you do timer = NSTimer.schedule...
At the beginning of your class:
var spawnBulletsTimer : NSTimer?;
var spawnMeteorsTimer : NSTimer?;
var onTimer: NSTimer?;
When creating the timers:
spawnBulletsTimer = NSTimer.scheduledTimerWithTimeInterval(0.2, target: self, selector: Selector("SpawnBullets"), userInfo: nil, repeats: true)
spawnMeteorsTimer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: Selector("SpawnMeteors"), userInfo: nil, repeats: true)
onTimer = NSTimer.scheduledTimerWithTimeInterval(timeInterval, target: self, selector: Selector("onTimer:"), userInfo: nil, repeats: true)
Then when you need to pause:
onTimer?.pause()
spawnBulletsTimer?.pause()
spawnMeteorTimer?.pause()
Then when you need to resume:
onTimer?.resume()
spawnBulletsTimer?.resume()
spawnMeteorTimer?.resume()
How can I pause and resume NSTimer.scheduledTimerWithTimeInterval in swift?
You need to invalidate it and recreate it. You can then use an isPaused
bool to keep track of the state if you have the same button to pause and resume the timer:
var isPaused = true
var timer = NSTimer()
@IBAction func pauseResume(sender: AnyObject) {
if isPaused{
timer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: Selector("somAction"), userInfo: nil, repeats: true)
isPaused = false
} else {
timer.invalidate()
isPaused = true
}
}
Unable to pause Game Scene when home button pressed
You can set an observer for UIApplication.willResignActiveNotification
like this, without using your custom notification:
let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self, selector: #selector(appMovedToBackground), name: UIApplication.willResignActiveNotification, object: nil)
@objc func appMovedToBackground {
// You will need to pause the game here, save state etc.
// e.g. set SKView.isPaused = true
}
This page from Apple contains more information. It states that SKView.isPaused
should be set automatically when an app is sent to the background.
One point to consider. If the nodes’ movement is based on a timer relative to an absolute point in time, this would have the effect of updating the positions as if they had been moving while in the background.
Finally, are you calling isPaused
on the SKScene
?
How to make iPhone application go to pause menu when home button is clicked?
The Appdelegate.m of your app provides functions you can use to track if the Application will be entering the background;
User pressed the button;
- (void)applicationWillResignActive:(UIApplication *)application
Application is in the background;
- (void)applicationDidEnterBackground:(UIApplication *)application
Within any of these functions you could set the BOOL to True/YES. -> See the comments provided by Apple within the functions for their exact usage.
When the application becomes active again, the appdelegate will (again) fire a function;
- (void)applicationDidBecomeActive:(UIApplication *)application
Swift, SpriteKit - Pause whole script
Pausing within the GameScene
Pausing the scene:
self.paused = true
(self
is the GameScene
).
Pausing the view (SKView
):
self.view?.paused = true
Pausing within the GameViewController
Pausing the scene:
let skView = self.view as! SKView
skView.scene?.paused = true
Pausing the view (SKView
):
let skView = self.view as! SKView
skView.paused = true
To unpause just set paused
property to false
.
Related Topics
How to Add a Link for a Rate Button with Swift
How to Change the Font Size of a Uilabel in Swift
How to Read Heart Rate from iOS Healthkit App Using Swift
Start/Stop Image View Rotation Animations
iOS with Parse. Pfuser.Currentuser() Not Getting Cached. Returns Nil After App Restart
Get Index of Object from Array of Dictionary with Key Value
Passing Data Between View Controllers Without Segue
Reload View When @Published Is Changed
Why Protocol Is Better Than Class in Swift
How to Center a Label Horizontally for All iOS Devices in Swift
Show Two Different Custom Cells in Same Uitableview - Swift Firebase
How to Add a Ibaction to a Button Programmatically in Swift 4
How to Add Images as Text Attachment in Swift Using Nsattributedstring
Swift Lazy and Optional Properties
Programmatically Set Uipageviewcontroller Transition Style to Scroll