0

我正在为 Android/OUYA 和 PC 在 Java 上创建一个多平台(但支持 OpenGL)游戏引擎,并且在快速检查游戏手柄状态时,PC 平台适配器给了我一些问题。

我目前正在使用 LWJGL/JInput 编写 PC 适配器,并且每当我以超过每秒 30 次的速度轮询游戏手柄状态时(大约 33 毫秒进行轮询和更新状态),从游戏手柄获得的值都是错误的。假的意思是摇杆可以在右边的一半,但 getAxisValue 返回 0 而不是 1f 中接近 0.5f 的东西。最重要的是,它似乎需要比 33ms 更长的时间,否则当被要求更频繁地执行此操作时会很好。是什么赋予了?

简而言之,在典型的更新调用中发生的情况是,引擎会扫描活跃玩家的控制器,以了解游戏中实际使用的特定按钮的状态,所有这些都提前设置和注册。目前,在我的测试应用程序中,它由两个按钮和一个轴组成。所以它所做的只是检查三个输入的当前状态,仅此而已。在通过几层接口并进入一个开关块之后,最终这被称为:

return controller.isButtonPressed(map.A);

或者

return controller.getAxisValue(map.LS_H);

其中 map 包含将名称链接到给定控制器的特定索引值的最终整数。

我通过自己的测试发现:

  • 这不是硬件问题,因为它在低于每秒 30 到 35 次更新时保持相当准确。
  • 当将速度提高到每秒更新约 60 次以匹配图形线程的 60fps 速率时,它只会导致输入线程的大量延迟。图形线程不受影响,这让我认为这也不是一般的性能问题。
  • 将 isButtonPressed 或 getAxisValue 更改为任意预设值可解决更新滞后问题,因此不是我的代码导致间歇性停止,绝对是 isButtonPressed 和 getAxisValue。

有什么方法可以提高游戏手柄检查的速度,或者我错过的某个设置通过 LWJGL/JInput 禁用了不必要的输入例程?

在性能方面要求匹配 60fps 是否太多?

4

2 回答 2

0

轮询不是最好的方法,它是一个相对昂贵的操作。看一下 JInput 上的事件接口,应该可以快速查看事件队列的内容。

于 2014-08-05T22:07:14.000 回答
0

原来我遇到的部分视觉延迟是由于我的循环的 delta-t 计算存在问题。它基于前一帧结束和新帧开始之间的时间,排除了对前一帧执行计算所花费的时间。这导致帧的视觉卡顿需要更长的时间,使任何小的性能问题都显得很大。修复此问题有助于视觉卡顿,但没有改善游戏手柄延迟(移动轴和看到结果之间的时间)或输入读数的准确性(轴物理上位于 X,但读数为 0 或非 X)。


什么解决了它:

我缩小了一些导致时间浪费的问题:

  • Display.update()自动轮询输入,这已经在逻辑线程中完成。从渲染线程调用它可能会导致线程之间的锁定问题,使逻辑线程等待渲染线程释放输入对象。另一个考虑是轮询现在发生的频率明显更高。使用Display.update(false)并让逻辑线程自行轮询大大减少了问题。

  • Display.setVSyncEnabled(true)强制渲染线程在我的 60hz 显示器上使用其给定的全部渲染时间(对于 60fps 速率为 13ms),这可能会加剧之前的锁定问题。在从Display.update()删除输入轮询之前,启用它总是会使逻辑线程的卡顿恶化

  • 可选地使用Display.swapBuffers()而不是Display.update(false)似乎对性能的改善很小。在我的代码中,后者往往会导致间歇性帧滞后。

实施这些更改后,我没有注意到游戏手柄读数有任何问题,并且引擎对轴的变化非常敏感。我在硬件上测试的没有视觉卡顿的最高速度是 60fps 渲染和逻辑/输入线程上的 100 个周期/秒。


我相信心理层面的部分问题是我试图独立于渲染过程来轮询输入硬件,由于 Display.update() 与输入轮询和屏幕缓冲区相关联,LWJGL 似乎并不鼓励这种做法. 通过API实现的方式,在没有建立显示的情况下使用一些输入设备是不可能的。

于 2014-08-05T23:59:16.287 回答