游戏键盘输入和事件

时间:2015-05-20 08:59:20

标签: c++ winapi keyboard game-engine

我正在开发一个小游戏引擎,无法决定如何处理键盘输入。到目前为止,我一直在通过从窗口过程中捕获WM_KEYDOWNWM_KEYUP消息来处理键盘输入,但是在我看来这并不是处理键盘输入的好方法。

我非常喜欢Infinity Ward 3.0引擎,您可以使用简单的配置文件或使用游戏控制台轻松更改每个键操作。我想这样做。

以下是来自IW 3.0引擎的配置文件的片段:

bind TAB "+scores"
bind ESCAPE "togglemenu"
bind SPACE "+gostand"
bind ALT "gocrouch"
bind CTRL "goprone"
bind SHIFT "+breath_sprint"
bind 1 "weapnext"
bind 2 "weapnext"
bind 4 "+smoke"
bind 5 "+actionslot 3"
bind 6 "+actionslot 4"
bind 7 "+actionslot 2"
bind ` "toggleconsole"
bind A "+moveleft"
bind B "mp_QuickMessage"
bind D "+moveright"
bind E "+leanright"

您甚至可以将其他操作分配给键,例如聊天中的内容:

bind F3 "say Hello, World!"

我已经有了配置文件,我正在游戏启动时阅读,之后我会初始化所有操作键。它有效,但将所有键分配给所有操作真的很不舒服。对于像A, B, C, D, E这样的键,这很容易,因为每个字符的ASCII码对应WM_KEYDOWN/UP消息,但对于像SPACE, CTRL, SHIFT这样的键则不然。

所以我的问题是:

  • 抓住钥匙的最佳方法是什么? (原始输入/窗口消息/获取(分配)KeyState)
  • 如何轻松地将配置文件中的密钥分配给 行动?
  • 做一些活动经理是个好主意吗?
    • 如果是这样,事件管理器结构应该如何?
  • 我应该为所有键和相应的操作分配数字,还是像“PlayerJump”,“PlayerForward”,“FireAction”......等字符串?

2 个答案:

答案 0 :(得分:2)

很抱歉迟到了回复帖子,我在最近2天没有回家。 我已经完成了这个问题。根据我的第一个问题,我选择原始键盘输入,如果有兴趣的话,这里是代码:

std::map<string, bool> myKey;
bool KEYBOARD_INPUT::GetRawKeyboardData(LPARAM lParam)
{
    char buffer[sizeof(RAWINPUT)];
    UINT size = sizeof(RAWINPUT);
    GetRawInputData(reinterpret_cast<HRAWINPUT>(lParam), RID_INPUT, buffer, &size, sizeof(RAWINPUTHEADER));

    RAWINPUT* raw = reinterpret_cast<RAWINPUT*>(buffer);
    if(raw->header.dwType == RIM_TYPEKEYBOARD)
    {
        const RAWKEYBOARD& rawKeyboard = raw->data.keyboard;

        unsigned int scanCode = rawKeyboard.MakeCode;
        unsigned int flags = rawKeyboard.Flags;
        const bool E0 = ((flags & RI_KEY_E0) != 0);
        const bool E1 = ((flags & RI_KEY_E1) != 0);
        const bool KeyDown = !((flags & RI_KEY_BREAK) != 0);

        UINT key = (scanCode << 16) | (E0 << 24);
        char buffer[32];
        GetKeyNameText((LONG)key, buffer, 32);
        if(KeyDown) // Press
        {
            myKey[buffer] = true;
        }
        else // Release
        {
            myKey[buffer] = false;
        }
    }
    return true;
}

这是获取实际按键状态的功能:

bool KEYBOARD_INPUT::KeyPressed(string key, int mode)
{
    if(mode == ONLYONCE)
    {
        if(myKey[key] && pressed_onlyonce[key] == false)
        {
            pressed_onlyonce[key] = true;
            return true;
        }
        if(!myKey[key])
        {
            pressed_onlyonce[key] = false;
            return false;
        }
    }

    else if(mode == CONTINUOUS)
    {
        if(myKey[key] == true)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    else if(mode == TOGGLE)
    {
        if(myKey[key] && pressed_toggle[key] == false)
        {
            pressed_toggle[key] = true;
            released_toggle[key] = !released_toggle[key];
            return released_toggle[key];
        }
        else if(!myKey[key])
        {
            pressed_toggle[key] = false;
            return released_toggle[key];
        }
    }
    return false;
}

我认为代码也是我其他问题的答案。 如果有人对此课程的完整源代码感兴趣,请在评论部分告诉我。

我想,我可以关闭这个帖子,我特别感谢@IInspectabl ,非常感谢你!

答案 1 :(得分:-3)

有很多方法。捕获密钥的好方法是使用ReadConsoleInput()然后 处理switch语句中的密钥代码。正如您在下面的代码中看到的那样 您也可以“绑定”switch语句中的键。

#include <stdio.h>
#include <windows.h>
#include <iostream>
using namespace std;




int main()
{
    DWORD        mode;          /* Preserved console mode */
    INPUT_RECORD event;         /* Input event */
    BOOL         EXITGAME = FALSE;  /* Program termination flag */
    unsigned int counter = 0;   /* The number of times 'Esc' is pressed */


    /* Get the console input handle */
    HANDLE hstdin = GetStdHandle( STD_INPUT_HANDLE );

    /* Preserve the original console mode */
    GetConsoleMode( hstdin, &mode );

    /* Set to no line-buffering, no echo, no special-key-processing */
    SetConsoleMode( hstdin, 0 );




    while (!EXITGAME)
    {           


        if (WaitForSingleObject( hstdin, 0 ) == WAIT_OBJECT_0)  /* if kbhit */
        {
            DWORD count;  /* ignored */

            /* Get the input event */
            ReadConsoleInput( hstdin, &event, 1, &count );
            cout<<"Key Code   = "<<event.Event.KeyEvent.wVirtualKeyCode <<" \n";

        }

            /* Only respond to key release events */
            if ((event.EventType == KEY_EVENT)
            &&  !event.Event.KeyEvent.bKeyDown)
            {        


                    switch (event.Event.KeyEvent.wVirtualKeyCode)
                    {
                        case VK_ESCAPE:
                           EXITGAME = TRUE;
                         break;

                        case VK_SPACE:

                         break;


                        case VK_RETURN:

                         break;

                        case VK_LEFT:
                            // left key   move player left
                            cout<<"VK_LEFT   = "<<event.Event.KeyEvent.wVirtualKeyCode <<" \n";

                         break;

                        case VK_RIGHT:
                            // right key   move player right
                            cout<<"VK_RIGHT   = "<<event.Event.KeyEvent.wVirtualKeyCode <<" \n";

                         break;    

                        case VK_UP:
                            // up key   move player up
                            cout<<"VK_UP   = "<<event.Event.KeyEvent.wVirtualKeyCode <<" \n";


                         break;

                        case VK_DOWN:
                            // up key   move player down
                            cout<<"VK_DOWN   = "<<event.Event.KeyEvent.wVirtualKeyCode <<" \n";


                         break;



                    }//switch

                   event.Event.KeyEvent.wVirtualKeyCode=-1;             


        }
    }

 return 0; 
}

虚拟键列表:https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx

ReadConsoleInput:https://msdn.microsoft.com/en-us/library/windows/desktop/ms685035(v=vs.85).aspx