【问题标题】:Using a timer vs update to run game SpriteKit使用计时器 vs 更新来运行游戏 SpriteKit
【发布时间】:2017-04-09 19:34:38
【问题描述】:

我很好奇在我的游戏中使用什么。计时器:

let goodFPS = SKAction.wait(forDuration: 0.01666)
let mainGameRunner = SKAction.run {
//my code is here
}
let toRepeat = SKAction.repeatForever(SKAction.sequence([goodFPS,mainGameRunner]))
inGameHighScore.run(toRepeat,withKey:"mainGame")

或更新函数:

override func update(_ currentTime: TimeInterval){
//my code is here
}

哪个提供更快更一致的更新?

注意:我的帧率在 45 到 58 范围内

【问题讨论】:

    标签: swift sprite-kit


    【解决方案1】:

    首先,我认为您以错误的方式处理 FPS 问题。你不能“强制”比设备给你的帧速率更快。如果您将游戏中的动作建立在每一帧都将保持一致的假设之上,那么您做错了。这实际上是他们早期的做法,因为 CPU 非常慢,而且从一代到新的差异一开始并不算太差。但是在较新的硬件上运行旧的 DOS 游戏会很棘手,因为帧速率太高以至于整个游戏机制变得不稳定或太快而无法玩。

    这里的概念是“随着时间的推移”思考,并缩小与两帧之间经过的时间相关的任何动作。

    update() 方法通过每帧提供当前系统时钟状态为您提供了这个机会。通过跟踪最后一帧的时间,您可以计算与当前帧的时间差,并使用该差来缩小您正在执行的操作。

    不建议使用计时器以一致的帧速率获取更新,也不实用。您可能会在给定的时间间隔调用更新闭包,但该闭包内的代码需要时间自行执行,并且根据您的游戏逻辑,它甚至可能具有不同的执行时间。所以也许暂停时间是一致的,但是在暂停之前和之后运行的代码可能不一致。那么如果你在较慢的 CPU 上运行游戏会发生什么?代码速度会发生更大的变化,使您的计时不准确。

    反对在游戏循环中使用SKAction 的另一点就是它们的本质。动作是内存中的一个对象,意味着可以被多个对象重用。例如,如果您正在执行“跳跃”动作,建议将该动作存储在某处,并在每次需要“跳跃”的东西时重用相同的对象,无论它是什么节点。您的游戏循环应该在每一帧都执行,而不是由不同的对象执行。操作也是一次性的。这意味着你可以杀死一个动作,即使它正在运行。如果您将游戏循环放入一个动作中,它可能会由SKScene 运行。如果您在场景中使用另一个动作,它会立即变成一个难题,因为除了让动作生效之外,只有两种方法可以删除动作:删除所有动作或使用标识符键创建动作并使用该键删除任何动作用那把钥匙。如果您还没有看到它,它会强制您将标识符放在场景将运行的每个动作上,并一个一个地删除它们。他们再次为错误打开了大门,这将摆脱您的游戏循环,因为请记住,动作是一次性的!那么也不能保证你的动作会在每一帧都被首先执行。

    为什么要使用update() 方法?仅仅因为它是在您的场景中构建的。无论如何,每一帧,update() 都会首先被调用。然后,动作被执行。您不能像通过操作那样意外刷新update() 方法。您不必小心导致内存泄漏的强/弱关系,因为您从闭包内部引用对象,就像您在操作中所做的那样。

    建议阅读:

    1. SKAction API reference
    2. SKScene API reference :阅读SpriteKit 中的帧处理。它将帮助您了解他们如何在每一帧中将所有内容组合在一起。

    我希望它能让事情变得更清楚。

    【讨论】:

      【解决方案2】:

      我很确定 SKAction 的计时工具基于调用 update 的同一游戏循环。

      SKAction 的优势在于它对你来说是一劳永逸的,而使用update 会在设置和检查一堆计时器变量时变得很尴尬。

      【讨论】:

      • 我一直在测试,但似乎都不是很好
      【解决方案3】:

      我没有大量使用 SpriteKit 的经验,但我确实有一些在 iOS 中制作游戏和动画的经验。

      有一个名为 CADisplayLink 的类在每次刷新屏幕时都会触发对委托的调用,这是一种更新屏幕的好方法,无论是在游戏中还是在动画中,因为您知道它会每一帧都被调用,仅此而已。

      我不确定 SpriteKit 是否使用该类来触发 update 方法,但我确信它使用了类似的东西。这通常称为运行循环。

      SKActions 在此运行循环之上运行。

      通过使用wait 操作创建您自己的运行循环,您不仅没有获得任何好处,还可能在逻辑运行方式中引入不一致。

      假设您将等待操作设置为 0.01 秒(为简单起见,我将其向下取整)。如果屏幕刷新速度比您预期的要快,并且动作每0.009 秒更新一次,第一次检查它时,它不会触发,因为在wait 命令上还有一个0.001 秒,所以另一个@ 987654330@ 秒将过去,您的代码将在0.018 秒后执行,而不是您想要的0.01。不仅如此,执行之间还会经过两帧。

      如果你使用update函数,你可以知道你的逻辑每次屏幕刷新都会执行一次,不再重复。

      【讨论】:

      • 嗨,Emilio - 这正是我想知道的! CADisplayLink 和 SpriteKit 中的 Update 一样吗?
      • @Fattie 这很难说,但我想说这可能是相同的机制。不过,我不会在 update() 上使用自定义 CADisplayLink
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-21
      • 1970-01-01
      • 2016-06-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多