【问题标题】:Strange "stutter" in box2D on different android devices不同安卓设备上box2D中奇怪的“口吃”
【发布时间】:2012-02-14 10:00:27
【问题描述】:

我正在使用 C++ 同时开发引擎和游戏,并且我正在使用 box2D 作为物理后端。我正在不同的安卓设备和三分之二的设备上进行测试,游戏运行良好,物理也是如此。但是,在我的银河选项卡 10.1 上,我偶尔会遇到一种“口吃”。这是一个 youtube 视频演示:

http://www.youtube.com/watch?v=DSbd8vX9FC0

运行游戏的第一台设备是 Xperia Play……第二台设备是 Galaxy Tab 10.1。不用说 Galaxy 标签的硬件比 Xperia Play 好得多,但 Box2D 在随机时间间隔内滞后。两台机器的代码完全相同。此外,引擎/游戏的其余部分实际上并没有滞后。整个时间,它以稳定的 60 fps 运行。因此,这种“口吃”似乎是从 box2D 实际读取值时出现的某种延迟或故障。

您看到移动的精灵会在渲染时检查它们是否有附加的实体,并根据实体的世界位置设置它们的位置值。所以在这个特定的过程中,box2D 似乎与应用程序的其余部分不同步。很奇怪。我意识到这是一个长镜头,但我想无论如何我都会把它贴在这里看看是否有人有想法......因为我完全被难住了。感谢您提前提供任何意见!

哦,附​​言我使用的是固定时间步长,因为这似乎是此类事情最常见的建议解决方案。我在我的桌面上开发这个时移到了一个固定的时间步骤,我遇到了一个更严重的类似问题,固定的步骤就是解决方案。就像我说的游戏以 60 fps 稳定运行,这是由低延迟计时器控制的,所以我怀疑简单的延迟是问题所在。再次感谢!

【问题讨论】:

  • 您是否尝试过输出物理步骤之间的时间,也许您的代码中存在错误导致它们不规则?
  • 只是为了确定,您是否只为时间步长的 Box2D 的 Step() 函数提供了一个文字浮点值,例如 1/60.0?你确定每秒调用 60 次?
  • @iforce2d 是的,在初始化时我设置了一个 1/60 的浮点数并将我的最大全局 FPS 限制为 60,这就是我传递给 step() 方法的全部内容。
  • @tm1rbrt 我会这样做并回复你...我没有打扰,因为我认为它肯定是物理代码无论如何都滞后了,所以追踪步骤时间只会确认怀疑。感谢大家的建议,我稍后会更新。
  • 似乎是使用 NDK 在 C/C++ 中访问系统时间的错误。它应该是低延迟的,但它似乎与不同版本的 android 不同,这是命中注定的。我称之为错误,因为这样的事情应该在所有平台上都是一致的。毕竟,如果您可以依靠获得准确的系统时间,那将是一个问题。有关更多信息,请参阅有关 Ovidiu 问题的我的 cmets。我可能会发布自己的答案,以提供更多详细信息+解决方法。

标签: android c++ android-ndk box2d


【解决方案1】:

正如我在 cmets 中提到的,这归结为计时器分辨率问题。我正在使用一个计时器类,它应该访问最高分辨率的系统计时器,跨平台。一切都很好,除了在 Android 方面,有些版本可以正常工作,有些版本不能。 Galaxy Tab 10.1 就是这样一个例子。

我最终重新编写了我的 getSystemTime() 方法,以使用 C++11 的一个新添加项 std::chrono::high_resolution_clock。这也很好用(除了 Android 之外的所有地方)......除了它还没有在任何 NDK 中实现 android。它应该在第 5 版的 ndk NDK R7 中实现,在本文发布时已完成 80%。

我对访问系统时间的各种方法或可以在 NDK 端建立可靠计时器的方法进行了一些研究,但归根结底是这些方法并非在所有平台上都支持。我经历了从头开始编写自己的引擎的痛苦过程,这样我就可以支持每个版本的 android,所以押注于实现不一致的方法是荒谬的。

在我看来,对于任何面临这个问题的人来说,唯一明智的解决方案就是简单地放弃在 NDK 端实现此类代码的想法。我将在 Java 端执行此操作,因为到目前为止,在我的所有测试中,这在我测试过的所有设备上都足够可靠。更多信息在这里:

http://www.codeproject.com/Articles/189515/Androng-a-Pong-clone-for-Android#Gettinghigh-resolutiontimingfromAndroid7

更新
我现在已经实现了我提出的解决方案,在 java 端进行计时,它已经奏效了。我还发现,在 NDK 端处理任何相对较大的数字,无论数据类型如何(例如调用单调时钟的纳秒数)也会导致某些版本的 android 严重滞后。因此,我通过传递指向系统时间的指针来尽可能优化这一点,以确保我们不会通过副本传递。

还有最后一件事,我认为从 NDK 端调用单调时钟不可靠的说法似乎是错误的。来自System.nanoTime() 上的 Android 坞站,

...和 ​​System.nanoTime()。这个时钟保证是单调的, 并且是通用间隔计时的推荐基础 用户界面事件、性能测量和其他任何东西 不需要测量设备睡眠期间经过的时间。

因此,如果可以相信,调用时钟似乎是可靠的,但如前所述,还会出现其他问题,例如处理分配和转储大量结果,这几乎将我的帧速率减半在装有 Android 3.2 的 Galaxy Tab 10.1 上。 最终结论: 平等地支持所有 android 设备要么几乎是不可能的,要么完全不可能,使用本机代码似乎会使情况变得更糟

【讨论】:

    【解决方案2】:

    我是游戏开发的新手,您似乎更有经验,问起来可能很愚蠢,但是您是否使用delta time 来更新您的世界?尽管您说您的帧速率恒定为 60 fps,但您的帧计数器可能计算错误,当 FPS 较低或您的世界似乎“落后”时,您应该使用delta time 跳过一些帧。我很确定您对此很熟悉,但我认为这里有一个很好的例子:DeltaTimeExample 虽然它是一个 C 实现。如果您需要,我可以从我的 Android 项目中粘贴一些关于我如何使用增量时间的代码,这些代码是我按照本书开发的:Beginning Android Games

    【讨论】:

    • 所以,我还没有确定问题的确切范围,但我现在知道了,多亏了你,这绝对是一个时间问题。我的代码使用它所在平台的低延迟系统计时器来限制 FPS,但我猜在不同版本的 android 上,“低延迟”部分似乎命中注定:S。我最初认为这是一个问题,因为 android 正在报告完整的 FPS……但后来意识到我的 fps 限制代码在它没有“准备好”时只是绕过渲染,无论如何都会报告完整的 FPS。
    • 我不确定是否要发布我自己的答案。我发布它的唯一原因是,我可以向遇到此问题的其他开发人员提供有关确切问题的更多信息(在我的回答中,我可以发布代码 sn-ps 之类的,这在 cmets 中会很草率)但相信如果可以的话,我会赞成你的问题 100X 大声笑。这是一个完美的例子,说明为什么不应该在凌晨 5 点之前进行编码。
    • 我很高兴这对您有所帮助。您可以发布您的答案/解决方案并接受它,以便它可以帮助其他人。我没有问题。
    • 谢谢。你的帖子确实有帮助,不幸的是它让我走上了一条令人失望的道路。事实证明,试图在 android 的 NDK 端获得可靠的时钟/计时器读数是不可能的。我将在我的答案中发布更多详细信息。
    猜你喜欢
    • 2023-03-16
    • 2012-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-12
    • 2018-01-06
    • 1970-01-01
    相关资源
    最近更新 更多