You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何暂停/恢复SpriteKit中通过SKAction实现的计时器

解决SpriteKit中SKAction计时器的暂停/恢复问题

核心思路

用SKAction实现的计时器,单纯依靠isPaused、speed或场景切换属性无法有效暂停的核心原因是:SKAction的计时进度绑定到节点/场景的运行周期,但场景切换或全局暂停可能无法精准中断已启动的wait动作的内部计时。最简便的可靠方案是手动记录剩余时间,暂停时终止当前计时动作,恢复时基于剩余时间重新启动。

具体实现步骤

  1. 添加属性存储计时状态
    在GameScene中定义两个属性,用于跟踪剩余时间和当前计时动作:
class GameScene: SKScene {
    // 剩余关卡时间(可根据需求设置初始值)
    var remainingTime: TimeInterval = 60.0
    // 标记计时动作的key,方便后续精准移除
    private var timerActionKey = "levelTimer"
}
  1. 封装计时器启动方法
    写一个通用的启动计时器方法,基于当前remainingTime创建动作序列:
func startTimer() {
    // 创建计时动作:等待剩余时间后触发超时逻辑
    let timerSequence = SKAction.sequence([
        SKAction.wait(forDuration: remainingTime),
        SKAction.run { [weak self] in
            self?.handleTimeOut() // 你的超时处理逻辑:游戏结束/进入下一关
        }
    ])
    // 用key标记动作,方便后续精准移除
    run(timerSequence, withKey: timerActionKey)
}

在场景初始化(比如didMove(to:))时调用startTimer()启动计时。

  1. 暂停计时器与切换菜单
    点击暂停按钮时,计算已流逝的时间、更新剩余时间,然后终止当前计时动作,再切换到MenuScene:
func pauseGame() {
    // 获取当前运行的计时动作
    guard let runningAction = action(forKey: timerActionKey) else { return }
    
    // 计算已流逝的时间:总时长 - 剩余时长(考虑speed影响)
    let elapsedTime = runningAction.duration - (runningAction.speed * runningAction.timeRemaining)
    remainingTime -= elapsedTime
    
    // 终止当前计时动作
    removeAction(forKey: timerActionKey)
    
    // 切换到MenuScene,传递剩余时间给菜单场景,方便恢复时使用
    let menuScene = MenuScene(size: size)
    menuScene.savedRemainingTime = remainingTime
    let transition = SKTransition.fade(withDuration: 0.3)
    transition.pausesOutgoingScene = false // 已手动终止计时器,无需系统暂停
    view?.presentScene(menuScene, transition: transition)
}
  1. 从菜单恢复游戏
    在MenuScene中添加恢复按钮的点击逻辑,传递保存的剩余时间回GameScene并重启计时器:
class MenuScene: SKScene {
    // 存储从GameScene传递来的剩余时间
    var savedRemainingTime: TimeInterval = 0.0
    
    func resumeGame() {
        let gameScene = GameScene(size: size)
        gameScene.remainingTime = savedRemainingTime
        let transition = SKTransition.fade(withDuration: 0.3)
        transition.pausesIncomingScene = false
        view?.presentScene(gameScene, transition: transition)
    }
}

如果是复用原GameScene实例(而非重新创建),只需回到场景后直接调用startTimer()即可。

为什么之前的方法无效?

  • 设置GameScene.isPaused = true:场景暂停后,若后续切换到MenuScene,原场景可能被系统释放或脱离运行周期,计时动作的暂停状态无法维持。
  • 调整SKTransition的暂停属性:仅控制场景切换过程中的暂停,无法影响已启动的SKAction的计时进度。
  • 设置节点isPaused或speed:若计时动作绑定的节点未被正确暂停(或被其他逻辑修改),则计时仍会继续。

内容的提问来源于stack exchange,提问作者oneshot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 12:27:58