轮询与事件驱动的输入


19

我正在开发使用轮询输入法的游戏。但是,既然我正在更深入地研究游戏菜单和其他UI组件,我发现我可能想拥有事件驱动的输入。甚至可以同时使用事件驱动的UI和轮询的“世界”输入。我对最好的方式是很好奇。

我将轮询定义为:每个更新循环都检查按下了哪些键,鼠标在哪里,按下了按钮,然后遍历它们并根据收集到的信息执行操作。

我将事件驱动定义为:基于中断的事件,当事件发生并触发中断并基于该事件运行代码块时。

您是否认为最好进行所有事件驱动,全部轮询,或者两者都可以接受?如果您有两者的优缺点,请列出。谢谢。

编辑

该游戏基于Java / OpenGL,因此将发布到Windows / Mac / Linux。将其扩展到移动设备的可能性很小。游戏是RTS风格的第三人称3D。

编辑2

我对实现此方法的方式仍然不完全满意,但是我要转向的是在UI中捕获事件,如果事件未由我的任何UI组件处理,我会将事件传递给用于选择的“世界”。就像是:

@Override  
private boolean handleEvent(Event event) {  
    if(hud.handleEvent(event)) {  
        return true;  
    }  
    return WORLD.handleEvent(event);  
}

这样,我不会从用户界面中泄漏点击以选择按钮后面的对象,而不是其他。

目前,我的摄像头控件仍然基于轮询,并且目前似乎可以正常使用,但稍后可能会进行更新。

我感谢所有答案,对不起,我只能选择其中一个!


6
我不确定使用Java,但总的来说,您总是必须轮询输入。然后,您可以在事情发生变化时发布事件,但这仍然基于轮询系统。
詹姆斯

我认为最相关的焦点是设计一个事件循环,该事件循环除了输入集合外没有其他负担。让我解释一下:操作系统将执行输入驱动的中断,并在全局“输入线程”中对其进行处理,然后此OS线程会将消息重定向到当前关注的应用程序中,并将intel写入其消息队列中。消息队列必须由PeekMessage或GetMessage轮询。最快的方法是使用GetMessage并让调度程序唤醒您,然后可以非常精确地为消息加时间戳。
v.oddou 2014年

Answers:


17

这取决于您的游戏和硬件的要求。大多数游戏通常会对输入状态的变化感兴趣,例如,用户按下开火键并开始发射武器,用户释放开火键并停止发射武器,用户按下移动键并开始移动,释放移动键并停止移动等等,因此在这些情况下,事件驱动的输入系统最有意义,因为信息已经采用了适当的格式。此外,在Windows平台上,您已经收到用于更改键盘和鼠标状态的事件,因此通常是从低级输入事件到高级游戏事件的1:1转换。使用轮询,您经常会发现自己不得不通过比较当前帧与最后一帧之间的状态来手动生成此类事件。基本上,“现在按下了哪些按钮?”

话虽这么说,但是在某些平台上,您只能在低级别上轮询输入,因此无法自行进行边缘检查。但是,我一直使用所有高级逻辑的事件来取得最佳结果,因为这自然是那些系统倾向于运行的方式。


谢谢,我提供了有关游戏平台和用途的其他信息。
MichaelHouse

1
请注意,这GetAsyncKeyState是在Win32上使用轮询的简单方法。
Macke

Derp,我在Nate Bross的评论中问了一个您要在此处处理的问题,所以我想我将对其进行完善。是否所有PC都提供与OS键盘事件关系的1:1硬件中断,并且哪种平台仅限于低级轮询?
michael.bartnett

@Macke:有时,防病毒软件会报告使用此API的程序,因为它们可以从整个全局系统接收按键,从而启用了恶意按键记录。在整个互联网上(我知道)关于它的最棒的文章是:securelist.com/analysis/publications/36358/…–
v.oddou

7

我认为没有理由你们不能同时做到这两个方面,并且要兼顾两全其美。

输入事件是通过轮询生成的(在某种程度上,驱动程序会轮询硬件以查看其状态),并且由于主循环会轮询所有输入设备,因此您可以轻松实现自己的设备。下面是我过去使用过的简单方法。

mouseInput = GetMouse();
kbInput = GetKeyboard();


// refactor this out to its own method if it makes sense
if menuState == Showing
    if mouseInput.LeftButton == State.Pressed
        LeftButton(mouseInput.X, mouseInput.Y)

// rest of game input code processing

void LeftButton(int x, int y)
{
    // left button event handler
}

我知道您将事件定义为中断,而我这里所说的并不是“真正基于事件”,但是我看不到上面没有给您带来中断的东西给您-大多数用户不会注意到单帧丢失,除非您的游戏以非常低的帧速率运行。


1
我很好奇从设备获得输入的本质。操作系统调度的键盘事件是设备驱动程序级别轮询的结果吗?还是键盘事件与中断相对应?还是有中断,但是操作系统会缓冲它们并在合适时分派它们?
michael.bartnett

我对它在该级别的工作方式并不满意,但是最基本的是,某些软件会循环运行,并检查键盘状态并将其与以前的状态进行比较,如果更改了更改,则更改会冒泡。
Nate

5

这里有两个不同的问题:

  1. 您如何从OS /硬件读取用户输入?

  2. 您如何处理引擎中的用户输入?

对于阅读而言,它显然取决于您的平台以及您想阅读哪种输入。请注意,在输入层中将一件事转换为另一件事很容易。(即,轮询事件并向引擎发出事件,或者侦听事件并向引擎发出状态。)

对于处理,有几种不同的选择:

  • 对于播放器移动控制(和类似方案),轮询可能更简单,因为您需要重新计算每帧的速度。您的内部循环很有可能基于轮询:

    即像 speed += 1 if button.down else -1; clamp(speed, 0, 42);

  • 对于离散事件(火弹,暂停游戏,传送到星球的另一侧),事件处理是可取的,否则您的代码会被maybeLaunchMissile(key_state);调用打乱,这很糟糕。;)

希望能帮助到你。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.