大型游戏中的输入管理技术


16

是否有用于管理大型游戏中输入的标准技术。当前,在我的项目中,所有输入处理都在游戏循环中完成,如下所示:

while(SDL_PollEvent(&event)){
            switch(event.type){
                case SDL_QUIT:
                    exit = 1;
                    break;
                case SDL_KEYDOWN:
                    switch(event.key.keysym.sym){
                        case SDLK_c:
                            //do stuff
                            break;
                    }
                    break;
                case SDL_MOUSEBUTTONDOWN:
                    switch(event.button.button){
                        case SDL_BUTTON_MIDDLE:
                                //do stuff
                                break;
                            }
                    }
                    break;
            }

(我正在使用SDL,但我希望主要实践也适用于库和框架)。对于大型项目,这似乎不是最佳解决方案。我可能有几个对象都想知道用户所按的内容,因此使这些对象处理输入更为有意义。但是,它们不能全部处理输入,因为一个事件发生后,它将被推入事件缓冲区,因此另一个对象将不会接收该输入。最常用的方法是什么?


使用事件管理器,您可以在输入中触发事件,并让游戏的所有其他部分注册到事件中。
danijar

@danijar,事件管理器到底是什么意思,是否可以提供一些基本的伪代码来显示您正在谈论的是什么?
w4etwetewtwet


1
我写了一个答案来详细说明事件管理器,这是我进行输入处理的方式。
danijar

Answers:


12

自从线程启动程序询问后,我将详细介绍事件管理器。我认为这是处理游戏输入的好方法。

事件管理器是一个全局类,它允许将回调函数注册到键并触发这些回调。事件管理器将注册的功能存储在按其键分组的专用列表中。每次触发键时,将执行所有已注册的回调。

回调可以是std::function可以容纳lambda的对象。键可以是字符串。由于管理器是全局的,因此您的应用程序组件可以注册到其他组件发射的密钥。

// in character controller
// at initialization time
Events->Register("Jump", [=]{
    // perform the movement
});

// in input controller
// inside the game loop
// note that I took the code structure from the question
case SDL_KEYDOWN:
    switch(event.key.keysym.sym) {
    case SDLK_c:
        Events->Fire("Jump");
        break;
    }
    break;

您甚至可以扩展此事件管理器,以允许将值作为附加参数传递。C ++模板对此非常有用。例如,您可以使用这样的系统为"WindowResize"事件传递新的窗口大小,以便侦听组件不需要自己获取它。这样可以大大减少代码依赖性。

Events->Register<int>("LevelUp", [=](int NewLevel){ ... });

我已经为我的游戏实现了这样的事件管理器。如果您有兴趣,我将在此处发布指向该代码的链接。

使用事件管理器,您可以轻松地在应用程序中广播输入信息。此外,这提供了一种让用户自定义按键绑定的好方法。组件侦听语义事件,而不是直接侦听键("PlayerJump"而不是"KeyPressedSpace")。然后,您可以具有一个输入映射组件,该组件侦听"KeyPressedSpace"并触发用户绑定到该键的任何操作。


4
好答案,谢谢。尽管我很想看代码,但我不想复制它,因此在实现自己的代码之前,我不会要求您发布它,因为我将以这种方式学习更多。
w4etwetewtwet

我只是想到了什么,我可以传递任何这样的成员函数,还是不必将寄存器函数带走AClass :: func,将其限制为一个类成员函数
w4etwetewtwet

这对于C ++中的lambda表达式来说是一件很棒的事情,您可以指定一个catch子句,[=]并且将从lambda访问的所有局部变量的引用都将被复制过来。因此,您不必传递this指针或类似的东西。但是请注意,您不能在老C函数指针中存储带捕获子句的lambda。但是,C ++ std::function可以正常工作。
danijar

std :: function很慢
TheStatehz '17

22

分成几层。

在最低层,您有来自操作系统的原始输入事件。SDL键盘输入,鼠标输入,操纵杆输入等。您可能有多个平台(例如,SDL是缺乏几种输入形式的最不常用的分母,稍后您可能会在意)。

您可以使用非常低级的自定义事件类型(例如“键盘按钮按下”等)来抽象这些内容。当您的平台层(SDL游戏循环)收到输入时,它应该创建这些低级事件,然后将其转发给输入管理器。它可以通过简单的方法调用,回调函数,复杂的事件系统来完成这些操作,无论您最喜欢什么。

输入系统现在可以将低级输入转换为高级逻辑事件。游戏逻辑完全不关心按下空格键。它关心JUMP被按下。输入管理器的工作是收集这些低级别的输入事件并生成高级别的输入事件。它负责知道空格键和“ A”游戏手柄按钮都映射到逻辑命令“跳转”。它处理游戏手柄与鼠标外观控件等。它发出的高层逻辑事件尽可能地从低层控件中抽象出来(这里有一些限制,但是在常见情况下您可以完全抽象掉东西)。

然后,角色控制器将接收这些事件并处理这些高级输入事件以进行实际响应。平台层发送了事件“向下键空格键”。输入系统接收到该消息,查看其映射表/逻辑,然后发送事件“ Pressed jump”。游戏逻辑/角色控制器接收到该事件,检查玩家是否真正被允许跳跃,然后发出“玩家跳跃”事件(或直接导致跳跃发生),其余的游戏逻辑将使用该事件来做任何事情。

任何依赖于游戏逻辑的东西都会进入玩家控制器。任何依赖于OS的东西都会进入平台层。其余的全部进入输入管理层。

这是一些业余的ASCII艺术来描述这一点:

-----------------------------------------------------------------------
Platform Abstraction | Collect and forward OS input events
-----------------------------------------------------------------------
                          | |
                          | |
                         \   /
                          \_/
-----------------------------------------------------------------------
    Input Manager    | Translate OS input events into logical events
-----------------------------------------------------------------------
                          | |
                          | |
                         \   /
                          \_/
-----------------------------------------------------------------------
Character Controller | React to logical events and affect game play
-----------------------------------------------------------------------
                          | |
                          | |
                         \   /
                          \_/
-----------------------------------------------------------------------
      Game Logic     | React to player actions and provides feedback
-----------------------------------------------------------------------

很酷的ASCII艺术,但不是必须的,对不起。我建议改为使用编号列表。无论如何都是一个很好的答案!
danijar

1
@danijar:嗯,我正在尝试,从未尝试过给出答案。比它值得的工作要多,但是比处理绘画程序要少得多的工作。:)
肖恩·米德迪奇

好吧,可以理解:-)
danijar

8
就个人而言,我更喜欢ASCII艺术方式而不是无聊的编号列表。
杰西·埃蒙德

@JesseEmond嘿,这里是艺术品吗?
danijar
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.