频繁检查 LWJGL/JInput 游戏手柄按钮或轴时出现延迟,如何解决?
Posted
技术标签:
【中文标题】频繁检查 LWJGL/JInput 游戏手柄按钮或轴时出现延迟,如何解决?【英文标题】:Lag when frequently checking LWJGL/JInput gamepad buttons or axis, how do I fix it? 【发布时间】:2014-08-05 02:41:04 【问题描述】:我正在为 android/OUYA 和 PC 在 Java 上创建一个多平台(但支持 OpenGL)游戏引擎,并且在快速检查游戏手柄状态时,PC 平台适配器给我带来了一些问题。
我目前正在使用 LWJGL/JInput 编写 PC 适配器,并且每当我以超过每秒 30 次的速度轮询游戏手柄状态时(大约 33 毫秒来进行轮询和更新状态),从游戏手柄获得的值是假的。假的意思是棒可以在右边的一半,但 getAxisValue 返回 0 而不是 1f 中接近 0.5f 的东西。最重要的是,它似乎需要比 33ms 更长的时间,否则当被要求更频繁地执行此操作时会很好。什么给了?
简而言之,在典型的更新调用中发生的情况是,引擎会扫描活跃玩家的控制器,以了解游戏中实际使用的特定按钮的状态,所有这些都提前设置和注册。目前,在我的测试应用程序中,它由两个按钮和一个轴组成。所以它所做的只是检查三个输入的当前状态,仅此而已。在经过几层接口并进入 switch 块之后,最终会调用它:
return controller.isButtonPressed(map.A);
或
return controller.getAxisValue(map.LS_H);
其中 map 包含将名称链接到给定控制器的特定索引值的最终整数。
我通过自己的测试发现的:
这不是硬件问题,因为它在每秒更新 30 到 35 次以下时保持相当准确。 当将速度提高到大约每秒 60 次更新以匹配 图形线程的 60fps 速率,它会导致输入大量延迟 仅限线程。图形线程不受影响,这让我觉得 这也不是一般的性能问题。 将 isButtonPressed 或 getAxisValue 更改为任意预设值可解决更新滞后问题,因此不是我的代码导致间歇性停止,肯定是 isButtonPressed 和 getAxisValue。有没有什么方法可以提高游戏手柄检查的速度,或者我错过的某些设置会通过 LWJGL/JInput 禁用不必要的输入例程?
就性能而言,匹配 60fps 是否太过分了?
【问题讨论】:
【参考方案1】:轮询不是最好的方法,它是一个相对昂贵的操作。看一下JInput上的事件接口,应该可以很快的查看到事件队列的内容。
【讨论】:
我深入研究了 JInput 的源代码,了解它如何实际接收游戏手柄状态,作为一种操作,由于在生成事件时内部缓存,轮询单个状态非常便宜。如果我改为处理事件而不是检查单个值,它不会解决问题,因为poll()
(JInput 确定何时查找要生成的事件的方法)在不同的线程上发生得太频繁了隐藏在Display.update()
中的功能(见我的回答)。
在实践中,关于每秒 T 次扫描“M
【参考方案2】:
原来我遇到的部分视觉延迟是由于我的循环的 delta-t 计算存在问题。它基于前一帧结束和新帧开始之间的时间,排除了对前一帧执行计算所花费的时间。这导致帧的视觉卡顿需要更长的时间,使任何小的性能问题都显得很大。修复此问题有助于视觉卡顿,但没有改善游戏手柄延迟(移动轴和看到结果之间的时间)或输入读数的准确性(轴物理上位于 X,但读数为 0 或非 X)。
解决了什么问题:
我缩小了一些导致时间浪费的问题:
Display.update() 自动轮询输入,这已在逻辑线程中完成。从渲染线程调用它可能会导致线程之间的锁定问题,使逻辑线程等待渲染线程释放输入对象。另一个考虑因素是投票现在发生的频率显着增加。使用 Display.update(false) 并让逻辑线程自行轮询大大减少了问题。
Display.setVSyncEnabled(true) 强制渲染线程在我的 60hz 显示器上使用其给定的全部渲染时间(60fps 速率为 13ms),这可能会加剧之前的锁定问题.在从 Display.update()
中删除输入轮询之前,启用它总是会恶化逻辑线程的卡顿可选地使用 Display.swapBuffers() 而不是 Display.update(false) 似乎对性能的改善很小。在我的代码中,后者往往会导致间歇性的帧延迟。
在实施这些更改后,我没有注意到游戏手柄读数有任何问题,并且引擎对轴的变化非常敏感。我在硬件上测试过的没有视觉卡顿的最高速度是 60fps 渲染和 100cycles/second 在逻辑/输入线程上。
我相信心理层面的部分问题是我试图独立于渲染过程轮询输入硬件,由于 Display.update() 与输入轮询和屏幕缓冲区。按照API的实现方式,有些输入设备在没有建立显示的情况下是无法使用的。
【讨论】:
以上是关于频繁检查 LWJGL/JInput 游戏手柄按钮或轴时出现延迟,如何解决?的主要内容,如果未能解决你的问题,请参考以下文章
如何编写程序可以检测 C++ 中游戏手柄按钮的信号? [关闭]