OpenGL学习笔记——处理键盘输入

用GLFW处理用户键盘输入有两种方式,一种是使用回调函数,一种是在每一次游戏循环中处理。这两种方法的最大差别在于是否能连续获得键盘输入,第二种方法可以。

一、回调函数

方法介绍

GLFW官方文档 对这种方法的讲解很详尽,下面只简单记录一下要点。
我们只需要自定义回调函数key_callback,并在进入游戏循环前调用函数glfwSetKeyCallback(window, key_callback)即可。下面简单介绍回调函数包含的内容。

函数头为void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods),其中,

key为按键,例如GLFW_KEY_UP,如果敲下的键不能被GLFW识别,比如Play和E-mail,key值就是GLFW_KEY_UNKNOWN;

scancode是每个平台自定义的表示按键的代码,当key值为GLFW_KEY_UNKNOWN时scancode会被用来识别键,否则scancode会被忽略;另外它可以和key一起用来获得键的名字const char* key_name = glfwGetKeyName(GLFW_KEY_W, 0);,第二个参数就是scancode。scancode可以通过const int scancode = glfwGetKeyScancode(GLFW_KEY_X);获得;

action代表动作类型,有

  • GLFW_PRESS:按下
  • GLFW_RELEASE: 松开
  • GLFW_REPEAT:重复按键

其中需要特别注意的是GLFW_REPEAT。引用Stack Overflow上的一个回答来解释它的意义:

Ask yourself, what is the frequency at which GLFW_REPEAT triggers? The right answer is that this frequency depends on your user's settings. It is exactly the frequency at which characters will appear in any input field in any application if you hold a character key. So the only purpose of GLFW_REPEAT is to implement printing in your application and make it look consistent with all other applications on the machine. You definitely should not use GLFW_REPEAT to implement WASD controls and other things like that.

也就是说如果我们希望在游戏中通过键盘控制一个人物的移动的话,是不能依靠GLFW_REPEAT让人物跑起来的,一个原因是移动速度不由程序员控制,容易引起游戏混乱,另一个原因是,如果像下面这样定义回调函数:

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    switch (key)
    {
        // change the position of the camera
        case GLFW_KEY_UP:
            camera_y += camera_speed;
            break;
        case GLFW_KEY_DOWN:
            camera_y -= camera_speed;
            break;
        ...
    }
}

连续按“↑”键会发现摄像机位置先上移一个camera_speed的长度,卡顿一会儿,才开始连续向上移动的。当游戏人物逃避Boss追杀时,我们应该不希望他先呆住一两秒再跑吧?因此要实现连续移动的效果就需要用到第二种方法,而非通过回调函数。

mods是"modifier bits"的简写,有

  • GLFW_MOD_SHIFT:按下Shift键
  • GLFW_MOD_CONTROL:按下Ctrl键
  • GLFW_MOD_ALT:按下Alt键
  • GLFW_MOD_SUPER:无

通过key和mods的组合就可以实现诸如Ctrl+N之类的操作。

何时使用

  • 按键速度不是特别快,不需要连续效果(比如人物不停地跑)
  • 要处理文本输入相关事件

二、循环中处理

方法介绍

这种方法的使用方式如下:

while (!glfwWindowShouldClose(window))
    {
        processInputs(window);
        ...
    }

processInputs中包含的要素和上面介绍的回调函数差不多,只是用到了另一个GLFW的函数glfwGetKey。最终效果上,这个函数返回任意时间某个键的状态,就是这个函数使得连续效果得以实现。processInputs可以这样实现:

void processInputs(GLFWwindow* window)
{
    // move the camera
    if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS)
        camera_x -= camera_speed;
}

何时使用

  • 对按键速度要求高甚至是一直按着,需要连续效果

glfwGetKey被调用前键被松开了怎么办

除了用户的操作外,函数glfwSetInputMode也会影响到glfwGetKey的返回值。

void glfwSetInputMode(GLFWwindow* window, int mode, int value)

当mode为GLFW_STICKY_KEYS且value为GLFW_TRUE时,只要按下一个键,那么glfwGetKey返回的该键的状态一定是按下的,哪怕在glfwGetKey函数被调用前这个键又被松开了。也就是说,当我们只关心键是否被按下过、而不关心它是何时被按下的时,就可以设置这个状态。

文本输入

GLFW可以接受Unicode字符流作为输入,从而允许程序处理来自用户的文本输入。我们可以将接受的Unicode字符转换成ASCII等其他格式的字符。

在游戏循环前需要调用函数glfwSetCharCallback(window, character_callback);

回调函数的函数头为void character_callback(GLFWwindow* window, unsigned int codepoint)

posted @ 2020-02-17 13:06  Irene_f  阅读(5855)  评论(0编辑  收藏  举报