• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

ios - 在Swift中“暂停”游戏

[复制链接]
菜鸟教程小白 发表于 2022-12-11 18:18:19 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题

我在Swift中创建了一个游戏,其中涉及怪物的出现。怪物会根据计时器的出现和消失,如下所示:

func RunAfterDelay(_ delay: TimeInterval, block: @escaping ()->()) 
{
    let time = DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)

    DispatchQueue.main.asyncAfter(deadline: time, execute: block)
}

然后我就这样称呼它(例如在2秒后生成):
///Spawn Monster
RunAfterDelay(2) { 
                [unowned self] in
                self.spawnMonster()
 }

然后,我进行了类似的隐藏操作(在x秒后,我将怪物消灭了)。

因此,我在屏幕顶部创建了一个设置图标,当您点击它时,会出现一个巨大的矩形窗口以更改游戏设置,但自然的问题是怪物仍然在背景中生成。如果我将玩家带到另一个屏幕,我相信我会失去我所有的游戏状态,并且必须重新开始才能回到它的状态(玩家可能处于游戏的中间)。

有没有办法告诉我以上创建的所有游戏计时器,即
DispatchQueue.main.asyncAfter(deadline: time, execute: block)

要暂停并继续说话吗?我想用所有计时器都可以(如果没有一种方法可以标记和暂停某些计时器)。

谢谢!



Best Answer-推荐答案


我已经解决了这个问题,并希望在下面的结论中分享我的时间研究/编码。为了更简单地陈述问题,我实际上想实现这一目标(不仅仅是简单地使用SpriteKit场景暂停,这很容易):

  • 在Swift中启动一个或多个计时器
  • 停止所有计时器(当用户按下暂停时)
  • 当用户取消暂停时,所有计时器都会重新启动,即,它们从停止运行

  • 有人向我提到,因为我正在使用DispatchQueue.main.asyncAfter,所以无法按我想要的方式暂停/停止(可以取消,但我离题了)。毕竟,我正在做asyncAfter。但是要真正使用计时器,您需要使用NSTimer(在Swift3中现在称为Timer)。

    经过研究,我发现实际上不可能暂停/取消暂停,因此当您想重新启动已暂停的计时器时,可以通过为每个计时器创建一个新计时器来“作弊”。我的结论如下:
  • 每个计时器启动时,记录您所需的延迟(我们将访问后者),并记录该计时器“触发”的时间。因此,例如,如果它在3秒内开始执行代码,然后将时间记录为Date()+ 3秒。我使用以下代码实现此目的:
  • //Take the delay you need (delay variable) and add this to the current time
    
    let calendar = Calendar.current        
    let YOUR_INITIAL_TIME_CAPTURED = calendar.date(byAdding: .nanosecond, value: Int(Int64(delay * Double(NSEC_PER_SEC))), to: Date())!
    
  • 现在,您已经记录了计时器将触发的时间,您可以等待用户按下Stop键。完成后,您将使用.invalidate()使每个计时器无效,并立即记录停止的时间。实际上,在这一点上,您还可以完全计算用户启动时所需的剩余延迟:
  • //Calculate the remaining delay when you start your timer back
    let elapsedTime = YOUR_INITIAL_TIME_CAPTURED.timeIntervalSince(Date)
    let remainingDelay = YOUR_INITIAL_TIMER_DELAY - elapsedTime
    
  • 当用户点击启动时,您可以通过简单地创建新的计时器来再次启动所有计时器,利用上述剩余时间(remainingDelay)和viola`,您将拥有新的计时器。

  • 现在,因为我有多个计时器,所以我决定需要在AppDelegate(通过服务类访问)中创建一个词典,以保留所有 Activity 计时器。每当计时器结束时,我都会将其从字典中删除。我最终制作了一个特殊的类,该类具有计时器,初始延迟及其启动时间的属性。从技术上讲,我可以使用数组,也可以将timer键放在该类上,但是我离题了。

    我创建了自己的addTimer方法,该方法将为每个计时器创建一个唯一的键,然后在计时器的代码完成后,将按以下方式自动删除:
      let timerKey = UUID().uuidString
    
    let myTimer: Timer = Timer.scheduledTimer(withTimeInterval: delay, repeats: false) {
                _ in
                   block()
                   self.timers.removeValue(forKey: timerKey)
                }
    
            }
    

    注意:block()只是调用您包装在计时器中的任何块。例如,我做了一些很酷的事情:
    addTimer(delay: 4, repeating: true)
            { [unowned self] in
                self.spawnMonster()
            }
    

    因此,addTimer将运行self.spawnMonster代码(作为block()),然后在完成后将其从字典中自动删除。

    后来我变得更复杂了,做了一些事情,例如保持重复计时器的运行而不是自动删除,但是出于我的目的,这只是很多非常具体的代码,可能会占用太多的回复时间

    无论如何,我真的希望这对某人有帮助,并希望回答任何人遇到的任何问题。我花了很多时间!

    谢谢!

    关于ios - 在Swift中“暂停”游戏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41054306/

    回复

    使用道具 举报

    懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    关注0

    粉丝2

    帖子830918

    发布主题
    阅读排行 更多
    广告位

    扫描微信二维码

    查看手机版网站

    随时了解更新最新资讯

    139-2527-9053

    在线客服(服务时间 9:00~18:00)

    在线QQ客服
    地址:深圳市南山区西丽大学城创智工业园
    电邮:jeky_zhao#qq.com
    移动电话:139-2527-9053

    Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap