简体   繁体   English

经常检查LWJGL / JInput游戏手柄按钮或轴时滞后,如何解决?

[英]Lag when frequently checking LWJGL/JInput gamepad buttons or axis, how do I fix it?

I'm in the process of creating a multiplatform (but OpenGL favoring) game engine on Java for Android/OUYA and PC, and the PC platform adapter is giving me some issues when rapidly checking gamepad state. 我正在为Android / OUYA和PC在Java上创建多平台(但受OpenGL支持)游戏引擎的过程,并且PC平台适配器在快速检查游戏手柄状态时给了我一些问题。

I'm currently using LWJGL/JInput to write the PC adapter, and whenever I poll gamepad state faster than about 30 times a second (giving about 33ms to do the poll and update the state), the values obtained from the gamepad are false. 我当前正在使用LWJGL / JInput编写PC适配器,并且每当我轮询游戏手柄状态的速度快于每秒30次左右(给与大约33ms的时间来进行轮询和更新状态)时,从游戏手柄获得的值都是false。 False in the sense that the stick can be halfway to the right, and yet getAxisValue returns 0 instead of something near 0.5f out of 1f. 错误的意思是,操纵杆可以位于右侧的一半,但是getAxisValue返回0而不是1f中接近0.5f的值。 On top of that, it seems to take longer than the 33ms that would be fine otherwise when asked to do it more often. 最重要的是,它似乎比33ms更长的时间,否则它将被要求更频繁地执行。 What gives? 是什么赋予了?

In a nutshell, what happens on a typical update call is that the engine scans through the active players' controllers for the state of specific buttons that are actually used in the game, all set and registered ahead of time. 简而言之,在典型的更新呼叫中发生的是,引擎会在活动玩家的控制器中扫描游戏中实际使用的特定按钮的状态,这些按钮均已提前设置并注册。 At the moment, in my test app, that consists of two buttons and an axis. 目前,在我的测试应用程序中,它包含两个按钮和一个轴。 So all it's doing is checking the current state of three inputs, no more. 因此,它要做的就是检查三个输入的当前状态,仅此而已。 After being passed through a couple layers of interfaces and into a switch block, eventually this is called: 在经过几层接口并进入交换块之后,最终将其称为:

return controller.isButtonPressed(map.A);

or 要么

return controller.getAxisValue(map.LS_H);

where map contains final ints that link names to specific index values for the given controller. 其中map包含最终int,这些int将名称链接到给定控制器的特定索引值。

What I've found through my own testing: 我通过自己的测试发现了什么:

  • This isn't a hardware issue, as it stays pretty accurate when below 30 to 35 updates per second. 这不是硬件问题,因为当每秒更新少于30到35次时,它仍然非常准确。
  • When ramping the speed up to about 60 updates a second to match the 60fps rate of the graphics thread, it causes massive lag on the input thread only. 当将速度提高到每秒更新约60次以匹配图形线程的60fps速率时,它只会在输入线程上造成巨大的延迟。 The graphics thread is not affected, which makes me think that it isn't a general performance issue either. 图形线程不受影响,这使我认为它也不是一般的性能问题。
  • Changing isButtonPressed or getAxisValue to arbitrary preset values solves the update lag issues, so it isn't my code causing the intermittent stops, definitely isButtonPressed and getAxisValue. 将isButtonPressed或getAxisValue更改为任意预设值可解决更新滞后问题,因此不是我的代码导致间歇性停止,绝对是isButtonPressed和getAxisValue。

Is there any way to improve the speed of gamepad checking, or some setting somewhere that I missed that disables unnecessary input routines through LWJGL/JInput? 有什么方法可以提高游戏手柄检查的速度,或者我错过的某个设置会禁用通过LWJGL / JInput不必要的输入例程的设置?

Is matching 60fps too much to ask in terms of performance? 就性能而言,匹配60fps太多了吗?

Polling isn't the best way, it's a relatively expensive operation. 轮询不是最好的方法,它是一个相对昂贵的操作。 Take a look at the event interface on JInput, you should be able to check the contents of the event queue quickly. 看一下JInput上的事件接口,您应该能够快速检查事件队列的内容。

Turns out part of the visual lag I was experiencing was due to an issue with my loop's delta-t calculation. 原来,我遇到的部分视觉滞后是由于循环的delta-t计算问题。 It was based on the time between the end of the previous frame and the start of the new frame, throwing out the time taken to perform the calculations on the previous frame. 它是基于前一帧结束到新帧开始之间的时间,而不是花费在前一帧上执行计算所需的时间。 This led to a visual stutter on frames that took longer, making any small performance issue appear huge. 这导致花了更长的时间在框架上出现视觉停顿现象,使任何小的性能问题都显得十分严重。 Fixing this helped visual stuttering, but didn't improve gamepad lag (time between moving an axis and seeing the result) or accuracy of input readings (axis physically at X but reading as 0 or something non-X). 修复此问题有助于视觉上的结结,但并不能改善游戏手柄的滞后性(移动轴与看到结果之间的时间)或输入读数的准确性(轴物理上为X,但读数为0或非X)。


What Fixed It: 解决问题的方法:

I narrowed down some of the problems that were causing time wastage: 我缩小了导致浪费时间的一些问题:

  • Display.update() automatically polls the input, which is already being done in the logic thread. Display.update()自动轮询输入,该输入已在逻辑线程中完成。 It is possible that calling it from the rendering thread caused a locking issue between threads, making the logic thread wait for the rendering thread to release the input objects. 从渲染线程调用它可能导致线程之间的锁定问题,从而使逻辑线程等待渲染线程释放输入对象。 Another consideration is that polling is now happening significantly more often . 另一个考虑因素是,轮询现在发生的频率越来越高 Using Display.update(false) and letting the logic thread poll on its own reduced issues considerably. 使用Display.update(false)并让逻辑线程自己轮询可大大减少的问题。

  • Display.setVSyncEnabled(true) forced the rendering thread to use the entirety of its given rendering time (13ms for a 60fps rate) on my 60hz monitor, possibly exacerbating the previous locking issue. Display.setVSyncEnabled(true)强制渲染线程在我的60hz监视器上使用其给定的整个渲染时间(对于60fps速率为13ms),这可能会加剧以前的锁定问题。 Enabling it always worsened the logic thread's stutter before removing the input polling from Display.update() 启用它总是会使逻辑线程的结结恶化,然后再从Display.update()中删除输入轮询。

  • Optionally using Display.swapBuffers() instead of Display.update(false) seems to have a minimal improvement on performance. (可选)使用Display.swapBuffers()代替Display.update(false)似乎对性能的影响很小。 In my code, the latter tends to cause intermittent frame lag. 在我的代码中,后者往往会导致间歇性帧延迟。

After implementing these changes, I haven't noticed any issues with gamepad readings, and the engine is extremely responsive to axis changes. 实施了这些更改之后,我还没有注意到游戏手柄读数的任何问题,并且引擎对轴的更改非常敏感。 The highest I've tested without visual stutter on my hardware is 60fps rendering and 100cycles/second on the logic/input thread. 我在硬件上测试时没有视觉卡顿的最高性能是60fps渲染和逻辑/输入线程上100cycles / second。


I believe part of the issue on a mentality level is that I am attempting to poll input hardware independently of the rendering process, which LWJGL doesn't seem to encourage due to Display.update() being tied to both input polling and the screen buffers. 我认为从心态层面来看,问题的一部分是我试图独立于呈现过程来轮询输入硬件,由于Display.update()与输入轮询和屏幕缓冲区都相关,因此LWJGL似乎不鼓励这样做。 By the way the API is implemented, it is impossible to use some input devices without having established the display. 通过实现API的方式,在未建立显示的情况下不可能使用某些输入设备。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM