FPS 和 UPS 有什么区别,我应该在我的游戏循环中跟踪 UPS 吗?
What is the difference between FPS and UPS and should I keep track of UPS on my game loop?
当我找到术语 UPS 时,我正在寻找改进游戏循环以及如何为玩家提供更多性能选项的方法。我知道这意味着每秒更新一次,但它如何影响性能?我应该为此担心吗?
假设您有一个非常简单的游戏,只有一个线程和一个基本循环,例如“while(running) { get_input(); update_world_state(); update_video(); }
”。在这种情况下,您最终会得到“UPS = FPS”(并且没有理由将 UPS 与 FPS 分开跟踪);如果 GPU 难以跟上整个游戏的速度(例如,如果你每秒获得 15 帧,那么与图形无关的事情可能比它们应该花费的时间长 4 倍,即使你有 8 CPU在等待 GPU 完成时什么都不做)。
对于另一种选择,如果您有 2 个线程,其中一个线程执行“while(running) { get_input(); update_world_state(); }
”而另一个线程执行“while(running) { update_video(); }
”怎么办?在这种情况下,没有理由期望 UPS 与 FPS 有任何关系。这里的问题是大多数游戏都不够聪明,无法处理可变时间,所以你最终会得到更像“while(running) { get_input(); update_world_state(); wait_until_next_update_starts(); }
”的东西,以确保游戏不会 运行 太快(例如,本应以每小时 20 公里的速度行驶的汽车以每小时 200 公里的速度行驶,因为 update_world_state()
被调用得太频繁了)。根据具体情况,您可能会获得 60 UPS(无论 FPS 是多少);但是如果 CPU 跟不上游戏 can/will 仍然放慢速度,你可能会得到 20 UPS(不管 FPS 是多少)。当然,如果世界状态没有改变,就没有必要更新视频;所以你希望图形循环更像“while(running) { wait_for_world_state_update(); update_video(); }
”,其中 wait_for_world_state_update()
确保 FPS <= UPS(并且 wait_for_world_state_update()
returns 立即没有任何延迟UPS 正在跟上)。
除此之外的下一步是“tickless”。在这种情况下,您可能有一个高优先级线程监视用户输入并为输入事件分配时间戳(例如“在时间 = 12356 时用户发射了他们的主要武器”)并将它们存储在列表中。然后你可能会有第二个(优先级较低,以避免弄乱用户输入时间戳的准确性)线程,其主循环如“while(running) { next_frame_time = estimate_when__next_frame_will_actually_be_visible(); update_world_state_until(next_frame_time); update_video(); }
”,其中 update_world_state_until()
使用一大堆数学来预测游戏状态在特定时间点将是什么(并在考虑时间戳的同时消耗存储的用户输入事件列表)。在这种情况下,UPS 没有任何意义(您只关心 FPS)。这也复杂得多(由于在任何时间点计算世界状态都涉及数学);但最终结果就像拥有“无限 UPS”,而无需每帧多次更新世界状态的开销;它允许您隐藏任何图形延迟(例如,比他们应该看到的晚 16.66 毫秒看到的东西);这使得它明显优于其他选项(更平滑,性能问题导致模拟速度变化等的可能性大大降低)。
当我找到术语 UPS 时,我正在寻找改进游戏循环以及如何为玩家提供更多性能选项的方法。我知道这意味着每秒更新一次,但它如何影响性能?我应该为此担心吗?
假设您有一个非常简单的游戏,只有一个线程和一个基本循环,例如“while(running) { get_input(); update_world_state(); update_video(); }
”。在这种情况下,您最终会得到“UPS = FPS”(并且没有理由将 UPS 与 FPS 分开跟踪);如果 GPU 难以跟上整个游戏的速度(例如,如果你每秒获得 15 帧,那么与图形无关的事情可能比它们应该花费的时间长 4 倍,即使你有 8 CPU在等待 GPU 完成时什么都不做)。
对于另一种选择,如果您有 2 个线程,其中一个线程执行“while(running) { get_input(); update_world_state(); }
”而另一个线程执行“while(running) { update_video(); }
”怎么办?在这种情况下,没有理由期望 UPS 与 FPS 有任何关系。这里的问题是大多数游戏都不够聪明,无法处理可变时间,所以你最终会得到更像“while(running) { get_input(); update_world_state(); wait_until_next_update_starts(); }
”的东西,以确保游戏不会 运行 太快(例如,本应以每小时 20 公里的速度行驶的汽车以每小时 200 公里的速度行驶,因为 update_world_state()
被调用得太频繁了)。根据具体情况,您可能会获得 60 UPS(无论 FPS 是多少);但是如果 CPU 跟不上游戏 can/will 仍然放慢速度,你可能会得到 20 UPS(不管 FPS 是多少)。当然,如果世界状态没有改变,就没有必要更新视频;所以你希望图形循环更像“while(running) { wait_for_world_state_update(); update_video(); }
”,其中 wait_for_world_state_update()
确保 FPS <= UPS(并且 wait_for_world_state_update()
returns 立即没有任何延迟UPS 正在跟上)。
除此之外的下一步是“tickless”。在这种情况下,您可能有一个高优先级线程监视用户输入并为输入事件分配时间戳(例如“在时间 = 12356 时用户发射了他们的主要武器”)并将它们存储在列表中。然后你可能会有第二个(优先级较低,以避免弄乱用户输入时间戳的准确性)线程,其主循环如“while(running) { next_frame_time = estimate_when__next_frame_will_actually_be_visible(); update_world_state_until(next_frame_time); update_video(); }
”,其中 update_world_state_until()
使用一大堆数学来预测游戏状态在特定时间点将是什么(并在考虑时间戳的同时消耗存储的用户输入事件列表)。在这种情况下,UPS 没有任何意义(您只关心 FPS)。这也复杂得多(由于在任何时间点计算世界状态都涉及数学);但最终结果就像拥有“无限 UPS”,而无需每帧多次更新世界状态的开销;它允许您隐藏任何图形延迟(例如,比他们应该看到的晚 16.66 毫秒看到的东西);这使得它明显优于其他选项(更平滑,性能问题导致模拟速度变化等的可能性大大降低)。