我在互联网上搜索了很多次,却找不到这个问题的答案。我知道如何使用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秒钟,我希望计时器从它停止的地方继续
如果你能帮助我,我感谢你,谢谢。
答案 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从正确的时间点开始的初始计时器。