ios8 Swift SpriteKit - 在 swift 中暂停和恢复 NSTimers
ios8 Swift SpriteKit - Pause and Resume NSTimers in swift
我在网上搜索了很多次都没有找到这个问题的答案。我知道如何使用无效函数暂停和恢复 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 秒,我希望计时器从停止的地方继续
如果你能帮助我,我很感激谢谢你。
我不相信有办法 pause/resume NSTimer 以您所说的方式。您必须使用 timer.invalidate()
和 timer.fire()
。但是,也许您可以使用一个 int(从 5 开始,每秒下降一次)来跟踪初始计时器在再次触发之前有多少秒,一旦时间再次触发,请确保将新的 int 值传递给 start来自正确时间点的初始计时器。
有一种方法可以 pause/resume Timer
个实例,因为使用重复计时器我们知道下一个 fire date
.
这是一个简单的classSRTimer
和一个协议SRTimerDelegate
协议 SRTimerDelegate
protocol SRTimerDelegate : AnyObject {
func timerWillStart(_ timer : SRTimer)
func timerDidFire(_ timer : SRTimer)
func timerDidPause(_ timer : SRTimer)
func timerWillResume(_ timer : SRTimer)
func timerDidStop(_ timer : SRTimer)
}
Class SRTimer
class SRTimer : NSObject {
var timer : Timer?
var interval : TimeInterval
var difference : TimeInterval = 0.0
var delegate : SRTimerDelegate?
init(interval: TimeInterval, delegate: SRTimerDelegate?)
{
self.interval = interval
self.delegate = delegate
}
@objc func start(_ aTimer : Timer?)
{
if aTimer != nil { fire(self) }
if timer == nil {
delegate?.timerWillStart(self)
timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(fire), userInfo: nil, repeats: true)
}
}
func pause()
{
if timer != nil {
difference = timer!.fireDate.timeIntervalSince(Date())
timer!.invalidate()
timer = nil
delegate?.timerDidPause(self)
}
}
func resume()
{
if timer == nil {
delegate?.timerWillResume(self)
if difference == 0.0 {
start(nil)
} else {
Timer.scheduledTimer(timeInterval: difference, target: self, selector: #selector(start), userInfo: nil, repeats: false)
difference = 0.0
}
}
}
func stop()
{
if timer != nil {
difference = 0.0
timer!.invalidate()
timer = nil
delegate?.timerDidStop(self)
}
}
@objc func fire(_ sender : SRTimer)
{
delegate?.timerDidFire(self)
}
}
使您的 class 符合协议 SRTimerDelegate
并使用
初始化一个 SRTimer
实例
var timer : SRTimer!
timer = SRTimer(interval: 5.0, delegate: self)
方法
start()
调用委托方法 timerWillStart
并启动计时器。
pause()
保存当前日期和下一个触发日期之间的差异,使计时器无效并调用委托方法 timerDidPause
.
resume()
调用委托方法 timerWillResume
,使用保存的 difference
时间间隔创建一个临时单发计时器。当此计时器触发时,主计时器将重新启动。
stop()
调用委托方法 timerDidStop
并使计时器无效。
当计时器触发时,调用委托方法 timerDidFire
。
首先,让我这么说——仅使用 NSTimer 是不可能的,没有内置函数可以做到这一点(您可以围绕它构建逻辑,正如 Vadian 的回答所建议的那样)。但是。
为什么 NSTimer 不是个好主意
让我们停下来想一想。对于游戏对象和精确生成,您不应该首先使用 NSTimer
。问题是 NSTimer
的实现(引用文档):
Because of the various input sources a typical run loop manages, the
effective resolution of the time interval for a timer is limited to on
the order of 50-100 milliseconds. If a timer’s firing time occurs
during a long callout or while the run loop is in a mode that is not
monitoring the timer, the timer does not fire until the next time the
run loop checks the timer. Therefore, the actual time at which the
timer fires potentially can be a significant period of time after the
scheduled firing time.
NSTimer 还有其他问题,但这超出了该问题的范围。
解决方案
您可以做的是,您应该在每次更新调用中收听增量时间变化
let delta = currentPreciseTime - previousPreciseTime
现在,当您拥有该增量时,您可以拥有您的 counter : Double
,并且在每次更新时,您都将计数器增加增量。
let counter : Double
counter += delta
现在你的 "timer" 是正确的 运行,你可以用简单的条件检查你的时间段是否已经过去,或者用它做任何你想做的事情:
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
}
您可以轻松构建自己的非常简单的计时器 class 来完成它。还!这样您就可以控制更新调用中发生的事情,这是更新逻辑所属的地方。 Timer 通过允许在该模型之外执行方法来打破该模型——这可能是有意的,但通常不是)。
我每天都在生产中构建一个游戏 运行,这是我认为周期性事件最常见的解决方案,因为如果使用得当,它可以节省最多的资源。显然不适合所有情况,但绝对适合您的需要。
希望对您有所帮助!
我在网上搜索了很多次都没有找到这个问题的答案。我知道如何使用无效函数暂停和恢复 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 秒,我希望计时器从停止的地方继续
如果你能帮助我,我很感激谢谢你。
我不相信有办法 pause/resume NSTimer 以您所说的方式。您必须使用 timer.invalidate()
和 timer.fire()
。但是,也许您可以使用一个 int(从 5 开始,每秒下降一次)来跟踪初始计时器在再次触发之前有多少秒,一旦时间再次触发,请确保将新的 int 值传递给 start来自正确时间点的初始计时器。
有一种方法可以 pause/resume Timer
个实例,因为使用重复计时器我们知道下一个 fire date
.
这是一个简单的classSRTimer
和一个协议SRTimerDelegate
协议 SRTimerDelegate
protocol SRTimerDelegate : AnyObject {
func timerWillStart(_ timer : SRTimer)
func timerDidFire(_ timer : SRTimer)
func timerDidPause(_ timer : SRTimer)
func timerWillResume(_ timer : SRTimer)
func timerDidStop(_ timer : SRTimer)
}
Class SRTimer
class SRTimer : NSObject {
var timer : Timer?
var interval : TimeInterval
var difference : TimeInterval = 0.0
var delegate : SRTimerDelegate?
init(interval: TimeInterval, delegate: SRTimerDelegate?)
{
self.interval = interval
self.delegate = delegate
}
@objc func start(_ aTimer : Timer?)
{
if aTimer != nil { fire(self) }
if timer == nil {
delegate?.timerWillStart(self)
timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(fire), userInfo: nil, repeats: true)
}
}
func pause()
{
if timer != nil {
difference = timer!.fireDate.timeIntervalSince(Date())
timer!.invalidate()
timer = nil
delegate?.timerDidPause(self)
}
}
func resume()
{
if timer == nil {
delegate?.timerWillResume(self)
if difference == 0.0 {
start(nil)
} else {
Timer.scheduledTimer(timeInterval: difference, target: self, selector: #selector(start), userInfo: nil, repeats: false)
difference = 0.0
}
}
}
func stop()
{
if timer != nil {
difference = 0.0
timer!.invalidate()
timer = nil
delegate?.timerDidStop(self)
}
}
@objc func fire(_ sender : SRTimer)
{
delegate?.timerDidFire(self)
}
}
使您的 class 符合协议 SRTimerDelegate
并使用
SRTimer
实例
var timer : SRTimer!
timer = SRTimer(interval: 5.0, delegate: self)
方法
start()
调用委托方法 timerWillStart
并启动计时器。
pause()
保存当前日期和下一个触发日期之间的差异,使计时器无效并调用委托方法 timerDidPause
.
resume()
调用委托方法 timerWillResume
,使用保存的 difference
时间间隔创建一个临时单发计时器。当此计时器触发时,主计时器将重新启动。
stop()
调用委托方法 timerDidStop
并使计时器无效。
当计时器触发时,调用委托方法 timerDidFire
。
首先,让我这么说——仅使用 NSTimer 是不可能的,没有内置函数可以做到这一点(您可以围绕它构建逻辑,正如 Vadian 的回答所建议的那样)。但是。
为什么 NSTimer 不是个好主意
让我们停下来想一想。对于游戏对象和精确生成,您不应该首先使用 NSTimer
。问题是 NSTimer
的实现(引用文档):
Because of the various input sources a typical run loop manages, the effective resolution of the time interval for a timer is limited to on the order of 50-100 milliseconds. If a timer’s firing time occurs during a long callout or while the run loop is in a mode that is not monitoring the timer, the timer does not fire until the next time the run loop checks the timer. Therefore, the actual time at which the timer fires potentially can be a significant period of time after the scheduled firing time.
NSTimer 还有其他问题,但这超出了该问题的范围。
解决方案
您可以做的是,您应该在每次更新调用中收听增量时间变化
let delta = currentPreciseTime - previousPreciseTime
现在,当您拥有该增量时,您可以拥有您的 counter : Double
,并且在每次更新时,您都将计数器增加增量。
let counter : Double
counter += delta
现在你的 "timer" 是正确的 运行,你可以用简单的条件检查你的时间段是否已经过去,或者用它做任何你想做的事情:
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
}
您可以轻松构建自己的非常简单的计时器 class 来完成它。还!这样您就可以控制更新调用中发生的事情,这是更新逻辑所属的地方。 Timer 通过允许在该模型之外执行方法来打破该模型——这可能是有意的,但通常不是)。
我每天都在生产中构建一个游戏 运行,这是我认为周期性事件最常见的解决方案,因为如果使用得当,它可以节省最多的资源。显然不适合所有情况,但绝对适合您的需要。
希望对您有所帮助!