如何通过SpriteKit中的SKAction来暂停计时器运行。

huangapple go评论59阅读模式
英文:

How to pause a timer run through SKAction in SpriteKit

问题

在我的基于SpriteKit的游戏中,玩家需要在每个关卡中完成一定时间内的任务。在时间到期时,会调用游戏结束方法或下一关的方法。

由于我知道在不同的角度下,使用NSTimer与SpriteKit结合使用是不好的,所以我在我的GameScene中将定时器构建为一系列SKActions,如下所示:

private func runTimer(duration: TimeInterval) {
   let wait = SKAction.wait(forDuration: duration)
   let endLevel = SKAction.run { [weak self] in
      self?.handleEndLevel()
   }
   run(SKAction.sequence([wait, endLevel]), withKey: "timer")
}

由于我还有一个暂停按钮,用于显示MenuScene,以及一个恢复按钮,我想要实现的是暂停/恢复定时器。什么是正确的实现方式?

以下是我已经尝试但没有成功的方法:

  • GameScene的属性isPaused设置为true
  • GameViewController中,在呈现GameScene/MenuScene时设置SKTransitionpausesOutgoingScenepausesIncomingScene属性。
  • 引入一个timerNode作为场景的子节点,然后使用timerNode.run并设置其isPaused属性。
  • 使用.speed而不是.isPaused

所有这些方法都导致了相同的结果:即使游戏已经暂停并恢复,定时器仍然在运行,就好像它从未被暂停过,导致关卡在预定时间之前结束。由于我仍在学习SpriteKit,我对isPaused属性的理解是它用于确定是否执行动作,因此我认为已经运行的动作会被暂停,但这可能是我理解有误。

我知道可能有一个激进的解决方案:在暂停时调用removeAction(forKey: "timer"),同时存储删除时的时间,并通过一些计算在游戏恢复后设置另一个具有剩余时间的定时器。然而,这看起来不太美观和过于复杂,我无法相信苹果没有实现更简单的方法。

英文:

In my game built on SpriteKit the player has a set amount of time to complete each level, and on expiration either a game over method or a next level one is called.

Since I know that using NSTimer combined with SpriteKit is bad under different points of view, what I did in my GameScene is building the timer as a sequence of SKActions like this:

    private func runTimer(duration: TimeInterval) {
       let wait = SKAction.wait(forDuration: duration)
       let endLevel = SKAction.run { [weak self] in
          self?.handleEndLevel()
       }
       run(SKAction.sequence([wait, endLevel]), withKey: "timer")
}

Since I also have a pause button, which presents a MenuScene, and a resume button, what I'm trying to achieve is to pause/unpause the timer. What is the proper way to achieve this?

Here's what I already tried with no luck:

  • set GameScene property isPaused to true.
  • in GameViewController, setting the pausesOutgoingScene and pausesIncomingScene properties of SKTransition when presenting GameScene/MenuScene.
  • introducing a timerNode to add as a child to the scene, then saying timerNode.run and setting its isPaused property.
  • using .speed instead of .isPaused.

All of these lead to the same result: even if the game is paused and resumed, the timer runs as it was never paused, so ending the level before it is supposed to. Since I'm still learning SpriteKit, my understanding of the isPaused property is that it is used to determine wheter actions are performed, so I thought an already running action would be paused, this might be wrong on my part maybe tho.

I know there might be a drastic solution: I can call removeAction(forKey: "timer") on pause while storing the time at which it was removed, and with some calculation I can set up another timer with the amount of time left once the game is resumed. This looks not pretty and overcomplicated tho and I can't believe Apple did not implement something easier.

答案1

得分: 0

经过调试,我发现问题出在用户点击暂停按钮时,我会呈现另一个场景并在“ViewController”中将gameScene.isPaused设置为true。如果我在“GameScene”中设置isPaused属性,而不呈现其他场景,场景实际上会暂停。这种行为的原因对我来说仍然不清楚。

重要提示,必须使用SKAction.pause单独暂停和恢复SKAudioNodes,否则背景音乐会暂停,但在恢复时音频播放器状态和场景状态之间会有(小)偏移。

英文:

After a debug, I found out that the issue lies in the fact that when the user taps the pause button I'm presenting another scene and I'm setting gameScene.isPaused to true in the ViewController. If I set the isPaused property in the GameScene, without presenting other scenes, the scene actually pauses. The reason of this behaviour is still unclear to me.

An important note, SKAudioNodes must be paused and resumed separately using SKAction.pause, otherwise the background music will pause but on resume there will be a (small) offset between the audio player state and the scene state.

huangapple
  • 本文由 发表于 2023年5月30日 06:39:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/76360671.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定