重新打开游戏时执行"catching up"

Perform "catching up" when game is re-opened

什么是处理 "catching up" 游戏关闭时本应发生的所有操作的好方法?

示例:小塔。有供应品、商店、顾客:当一个人关闭游戏并在第二天打开它时,应用程序必须弄清楚发生的一切。

我们正在尝试通过快速模拟一切来计算这一点,基本上是从他们离开游戏时开始快速转发。不幸的是,这可能需要 20 秒或更长时间。

有什么更好的处理方法的建议吗?

这是一个很好但非常开放的问题。

有多种方法,有些方法可能比其他方法更好,具体取决于您的需要、实施能力和时间。作为一个非游戏开发者,我将尝试天真地回答它(编辑:非常)。

您的建议无异于通过加快所涉及的计时器来模拟没有用户交互的游戏。要实现这一点,您需要确定离散时间流逝的基本计数器,例如滴答声。当游戏重新开始时,你会做:

for (NSUInteger i = 0; i < numberOfTicksMissed; i++) {
    doGameStuffThatWeMissedForTick(i);
}

计数器 i 可能不是必需的参数 - 实际上它不应该是,因为它可能应该在游戏状态模型中隐式捕获,但关键是你实际上是赶上这个方法。

您可以通过 运行 尽可能多地在后台运行它来节省一些等待时间,但实际上,这只是分散了周期而不是减少了周期。

另一种方法是通过近似间接模拟游戏执行。这意味着您实际上 运行 不是通过所有步骤,而是 运行 通过该数字的某个除数,然后 "guesstimate" 中间发生的事情。

例如,也许游戏状态必然是随机的——你在某个地方有一个随机数,而你错过了 1000000 个滴答声。好吧,与其做所有 1000000 次,不如做 1000 次,并使用统计数据来模拟每个“1000-tick”中发生的事情。例如,我们知道,如果您掷一次或两次硬币,您可能会看到所有正面或所有反面 - 但如果您多次掷硬币,则每次出现的频率接近 0.5。

因此,如果您的游戏需要在每个滴答中抛硬币,那么每“1000 个滴答”进行一次滴答是不合理的,而是对 1000 次硬币抛掷的方差进行建模并得到一个数字是在更小的范围内,例如 0.48 到 0.52。顺便说一句,这还不够紧,但你明白了。

如果您不涉及随机性,您也可以使用数学来获得精确或近似精确的解决方案,前提是所讨论的系统本质上不是混沌的。这需要仔细研究系统。

在 Tiny Towers 的情况下,我的猜测是他们对游戏进行了优化,因此即使在您玩游戏时,计算机积累资源的速度和其他速度也不是通过模拟得出的,而是通过计时器得出的。所以你必须根据规则构建东西来获取资源,但是计算机每分钟获得 X 金,等等。由于涉及动画,它可能看起来不像那样,但这可能就是正在发生的事情。

总而言之,首先你需要了解被模拟的系统。

如果是确定性的,那么在保存或退出游戏时,游戏至少应该保存所有相关参数(使用类似纪念品的东西)。然后在那个时候或当您加载时,游戏可以使用您的分析来进行前向计算或近似。如果它对初始条件敏感(混乱),则需要使用精确计算。

如果不是确定性的,那么在saving/exiting之后你也会想要捕获涉及的变量,但是你的分析和前向计算需要使用一些统计方法来降低数量级涉及的滴答数。想想抛硬币的比喻。

示例:黄金积累

假设要恢复的唯一状态是恢复时计算机有多少金币。

如果计算机总是每秒获得 10 金币,那么我们可以 遍历所有缺失的报价...

  • 暂停:电脑有X金
  • 1000 秒后恢复
  • 秒0:电脑有X金
  • 第二个1:电脑有X+10金币
  • 第二个2:电脑有(X+10)+10金币 ...
  • second 1000: 电脑有 (10 + (10 + (10 +.... + (10 + X)))))... gold

我们会发现在开始的第 1001 秒,计算机有 X + 10,000 金币。

当然,这会很浪费。因为乘法是迭代加法,我们可以这样做:

  • 暂停
  • 1000 秒后恢复
  • 计算金币:电脑有X + (1000 * 10)金币
  • 开始

现在,如果金币的积累通常是随机的,那么也许在您玩游戏的过程中,这种随机性会引起一些兴趣。所以也许规则是每一秒,计算机要么获得 10 金币,要么获得 0 金币。这可能会让玩家更感兴趣,因为计算机可以继续 "hot streak" 并真正挑战玩家,或者冷连胜等

但是在模拟中不需要阴谋,因此可以根据 N 分钟后的预期 对黄金进行统计建模。当然,我们会取平均值,如果我们愿意,我们可以在其中引入一个小范围的随机性,这将是相当现实的。

例如,假设您说 "let's model this based on what would happen in 99.7% of scenarios."

根据可靠的 68-95-99.7 规则,3 个标准差是建模所需的紧密度。

所以,我们有:

  • 暂停
  • 1000 秒后恢复
  • 计算黄金标准偏差:sqrt( 1000 * 0.5 * (1-0.5)大约16
  • 1000 秒后找到随机模拟金币:X + (1000*0.5*10) + RANDOM(-1,1)*48*10

最坏的情况下,电脑有X+5480金币。

请注意,在 99.7% 的场景(4520 和 5480)中,理论极限(0 和 10000)与可能性范围之间存在 巨大 差异。这就是统计的力量。

这可以用来优化另一个 运行 不可预测的循环。例如,如果黄金达到 6000,您可能需要进行复杂的模拟。通过将场景限制在 99.7%,您甚至无需考虑它,因为最大可能值小于阈值。

现在请注意,复杂的系统并不总是这样工作的。所以说规则是:计算机每秒获得1金币,但是第一次总金币总和达到质数时,计算机失去所有金币。

喜欢:1,0,1,2,0,1,2,3,4,0,1,2,3,4,5,6,0,1,...

现在你必须找出素数定理和潜在的因子数,并做各种各样的事情。所以说真的,1000秒后,如果你有10金币,而电脑有100金币,需要200金币才能获胜,我们还要建模吗?

当然有一种方法,但我笨拙地指出的是,这个相对简单的系统的复杂性使得纯计算方法不可行 - 也许统计方法也是如此。

分块

我没有提到的一点是,将要分批完成的工作分块,先做必要的事情来实现用户交互,然后再让一切变得简单。

所以,假设我们正在制作一款游戏,其中计算机的 位置 很重要。那么我们可能会先问这样一个问题:计算机是否很快就会可见?

如果没有,那么我们可以继续渲染场景,而不用担心计算机是否可见。然后一旦场景被渲染出来,工作的重点就可以转移到计算机到底在哪里的问题上了。

这是一个幼稚的思考过程:

  1. 确定计算机是否可见需要(估计)多长时间?
  2. 找出计算机在一定公差范围内的位置需要多长时间?
  3. 玩家有可能接触到计算机之前的最短时间长度是多少?

游戏可能会执行以下操作:

  • 玩家在我们离开他的位置 X
  • 计算机距离 X 至少 1000 距离
  • 玩家最多可以向电脑移动,而电脑是玩家,在 10 秒内是 100 距离的总和
  • 除非距离为 500 或更近,否则玩家无法看到电脑
  • 我们可以在 10 秒内计算出计算机的准确位置

然后:

  • 首先,让我们渲染玩家场景并让他行动起来。
  • 同时,在一个低优先级的后台队列中,开始计算电脑位置
  • 玩家互动后,继续计算电脑位置,优先级更高
  • 玩家互动后,开始保持计算机位置相关活动的队列
  • 当计算机位置已知时,应用队列
  • 必要时重新渲染