ios8 Swift SpriteKit - 快速暂停和恢复NSTimers

时间:2015-08-11 04:26:16

标签: swift timer ios8 nstimer invalidation

我在互联网上搜索了很多次,却找不到这个问题的答案。我知道如何使用invalidate函数暂停和恢复NSTimers - timer.invalidate。而且我知道如何恢复它们。但我有一个SpriteKit游戏。当我暂停游戏时,我会停止所有内容和计时器。我知道我可以使用.invalidate来阻止它们,但是当我使它们失效时:

例如,假设我有一个连续运行的5秒计时器,它会产生一个块。

当计时器到达循环的第二个3并且我暂停游戏时,计时器无效。当我恢复时,现在计时器第二次回到0,我必须等待另外5秒。我希望它从它停止的地方继续,3,并等待2秒钟,以便块生成。

            blockGenerator.generationTimer?.invalidate()

            self.isGamePaused = true
            self.addChild(self.pauseText)

            self.runAction(SKAction.runBlock(self.pauseGame))

e`

当我恢复时:

blockGenerator.generationTimer = ...

我必须再等5秒钟,我希望计时器从它停止的地方继续

如果你能帮助我,我感谢你,谢谢。

3 个答案:

答案 0 :(得分:2)

有一种暂停/恢复NSTimer实例的方法,因为使用重复计时器我们知道下一个fire date

这是一个简单的课程Timer和一个协议TimerDelegate

协议TimerDelegate

protocol TimerDelegate {
  func timerWillStart(timer : Timer)
  func timerDidFire(timer : Timer)
  func timerDidPause(timer : Timer)
  func timerWillResume(timer : Timer)
  func timerDidStop(timer : Timer)
}

课程计时器

class Timer : NSObject {

  var timer : NSTimer!
  var interval : NSTimeInterval
  var difference : NSTimeInterval = 0.0
  var delegate : TimerDelegate?

  init(interval: NSTimeInterval, delegate: TimerDelegate?)
  {
    self.interval = interval
    self.delegate = delegate
  }

  func start(aTimer : NSTimer?)
  {
    if aTimer != nil { fire() }
    if timer == nil {
      delegate?.timerWillStart(self)
      timer = NSTimer.scheduledTimerWithTimeInterval(interval, target: self, selector: "fire", userInfo: nil, repeats: true)
    }
  }

  func pause()
  {
    if timer != nil {
      difference = timer.fireDate.timeIntervalSinceDate(NSDate())
      timer.invalidate()
      timer = nil
      delegate?.timerDidPause(self)
    }
  }

  func resume()
  {
    if timer == nil {
      delegate?.timerWillResume(self)
      if difference == 0.0 {
        start(nil)
      } else {
        NSTimer.scheduledTimerWithTimeInterval(difference, target: self, selector: "start:", userInfo: nil, repeats: false)
        difference = 0.0
      }
    }
  }

  func stop()
  {
    if timer != nil {
      difference = 0.0
      timer.invalidate()
      timer = nil
      delegate?.timerDidStop(self)
    }
  }

  func fire()
  {
    delegate?.timerDidFire(self)
  }

让您的课程符合协议TimerDelegate并使用

初始化Timer个实例
var timer : Timer!
timer = Timer(interval: 5.0, delegate: self)

<强>方法

start()调用委托方法timerWillStart并启动计时器。

pause()保存当前日期与下一个开火日期之间的差异,使计时器无效并调用委托方法timerDidPause

resume()调用委托方法timerWillResume,创建一个具有保存的difference时间间隔的临时单击计时器。当此计时器触发时,主计时器将重新启动。

stop()调用委托方法timerDidStop并使计时器无效。

当计时器触发时,将调用委托方法timerDidFire

答案 1 :(得分:1)

首先,让我这样说 - 只有NSTimer是不可能的,没有内置功能可以做到这一点(你可以根据Vadian建议的那样建立逻辑)。 BUT。

为什么NSTimer不是个好主意

让我们停下来思考一下。对于游戏对象和精确的产卵,你不应该首先使用NSTimer。问题是NSTimer(引用文档)的实现:

  

由于各种输入源,典型的运行循环管理,   定时器的时间间隔的有效分辨率限于开启   50-100毫秒的顺序。如果计时器的发射时间发生   在长时间标注期间或运行循环处于不是的模式时   监视计时器,计时器直到下次才开火   运行循环检查计时器。因此,实际的时间   计时器可能会在很长一段时间内发生火灾   预定的开火时间。

NSTimer还存在其他问题,但这超出了该问题的范围。

<强>解决方案

你可以做什么,你应该在每次更新通话中听取增量时间变化

let delta = currentPreciseTime - previousPreciseTime

现在,当您拥有该增量时,可以拥有counter : Double,并且在每次更新时,您都会按增量计算增量。

let counter : Double
counter += delta

现在你的&#34;计时器&#34;运行正常,您可以通过简单的条件检查您的时间段是否已经过去,或者随心所欲地做任何事情:

let SPAWN_OBJECT_AFTER : Double = 5.0
if counter > SPAWN_OBJECT_AFTER {

    // Do something on fire event
    self.spawn()

    // This line effectively restarts timer
    counter -= SPAWN_OBJECT_AFTER
}

您可以轻松构建自己的,非常简单的计时器类来完成它。也!通过这种方式,您可以控制更新调用中发生的情况,即更新逻辑所属的位置。计时器通过允许在外部执行方法来打破该模型 - 它可能是有意的,但通常不是这样。

我每天都在制作一个正在运行的游戏,这就是我说的最常见的定期事件解决方案,因为它可以在适当使用时节省大部分资源。显然不适合一切,但绝对符合你的需要。

希望它有所帮助!

答案 2 :(得分:0)

我不相信有一种方法可以按照你所说的方式暂停/恢复NSTimer。您必须使用timer.invalidate()timer.fire()。但是,也许您可​​以使用int(从5开始并每秒下降)来跟踪初始计时器再次触发之前的秒数以及再次触发时间,确保将新的int值传递给start从正确的时间点开始的初始计时器。