14

C ++を使用して、UbuntuでSDLを使用してOpenGLプログラミングに慣れてきました。周りを見回して実験した後、私は理解し始めています。SDL でのキーボード イベント処理についてアドバイスが必要です。

私は一人称カメラを持っていて、前、後ろ、左右に機銃掃射し、マウスを使って周りを見回すことができます。ここに私の processEvents 関数があります:

void processEvents()
{
    int mid_x = screen_width  >> 1;
int mid_y = screen_height >> 1;
int mpx = event.motion.x;
int mpy = event.motion.y;
float angle_y  = 0.0f;
float angle_z  = 0.0f;

while(SDL_PollEvent(&event))
{
    switch(event.type)
    {
        case SDL_KEYDOWN:
            switch(event.key.keysym.sym)
            {
                case SDLK_ESCAPE:
                    quit = true;
                    break;
                case SDLK_w:
                    objCamera.Move_Camera( CAMERASPEED);
                    break;
                case SDLK_s:
                    objCamera.Move_Camera(-CAMERASPEED);
                    break;
                case SDLK_d:
                    objCamera.Strafe_Camera( CAMERASPEED);
                    break;
                case SDLK_a:
                    objCamera.Strafe_Camera(-CAMERASPEED);
                    break;
                default:
                    break;
            }
            break;

        case SDL_MOUSEMOTION:
            if( (mpx == mid_x) && (mpy == mid_y) ) return;

            SDL_WarpMouse(mid_x, mid_y);

            // Get the direction from the mouse cursor, set a resonable maneuvering speed
            angle_y = (float)( (mid_x - mpx) ) / 1000;      
            angle_z = (float)( (mid_y - mpy) ) / 1000;

            // The higher the value is the faster the camera looks around.
            objCamera.mView.y += angle_z * 2;

            // limit the rotation around the x-axis
            if((objCamera.mView.y - objCamera.mPos.y) > 8)  objCamera.mView.y = objCamera.mPos.y + 8;
            if((objCamera.mView.y - objCamera.mPos.y) <-8)  objCamera.mView.y = objCamera.mPos.y - 8;

            objCamera.Rotate_View(-angle_y);

            break;

        case SDL_QUIT:
            quit = true;
            break;

        case SDL_VIDEORESIZE:
            screen = SDL_SetVideoMode( event.resize.w, event.resize.h, screen_bpp, SDL_OPENGL | SDL_HWSURFACE | SDL_RESIZABLE | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE );
            screen_width = event.resize.w;
            screen_height = event.resize.h;
            init_opengl();
            std::cout << "Resized to width: " << event.resize.w << " height: " << event.resize.h << std::endl;
            break;

        default:
            break;
    }
}
}

これが機能している間、いくつかの制限があります。最大のものと私の質問の目的は、押された最新のキーのみを処理するように見えることです。したがって、「s」を押して後方に歩き、「d」を押して右に機銃掃射すると、右に機銃掃射することになりますが、後方には移動しません。

誰かが SDL でのより良いキーボード処理、一度に複数のキー押下のサポートなどのために正しい方向に私を向けることができますか?

ありがとう

4

5 に答える 5

21

SDL は、すべてのキーの現在の状態を追跡します。この状態には、次の方法でアクセスできます。

SDL_GetKeyState()

そのため、反復ごとに、キーの状態に基づいて動きを更新できます。動きを滑らかにするには、更新間の経過時間に基づいて動きの大きさを更新する必要があります。

于 2009-08-10T03:25:37.677 に答える
14

適切なアプローチは、入力イベントを処理し、イベントの状態をある種の構造に保持するキーボード (「入力」) ハンドラーを作成することです (連想配列は良いですね - key[keyCode])。

キーボード ハンドラーは、「キーが押された」イベントを受信するたびに、キーを有効 (true) に設定し、キー ダウン イベントを取得すると、キーを無効 (false) に設定します。

次に、イベントを直接プルせずに一度に複数のキーをチェックできます。サブルーチンに渡すことなく、フレーム全体でキーボードを再利用できます。

いくつかの高速な擬似コード:

class KeyboardHandler {
    handleKeyboardEvent(SDL Event) {
        keyState[event.code] = event.state;
    }

    bool isPressed(keyCode) {
        return (keyState[keyCode] == PRESSED);
    }

    bool isReleased(keyCode) {
        return (keyState[keyCode] == RELEASED);
    }

    keyState[];
}

...

while(SDL Pull events)
{
    switch(event.type) {
        case SDL_KEYDOWN:
        case SDL_KEYUP:
                keyHandler.handleKeyboardEvent(event);
            break;
        case SDL_ANOTHER_EVENT:
                ...
            break;
    }   
}

// When you need to use it:
if(keyHandler.isPressed(SOME_KEY) && keyHandler.isPressed(SOME_OTHER_KEY))
    doStuff(TM);
于 2009-08-10T03:26:57.987 に答える
5

SDL2 を使用している場合は、 を使用しますSDL_GetKeyboardState

例:

const Uint8 *keyboard_state_array = SDL_GetKeyboardState(NULL);

SDL_PollEvent(&event);

if(event.type == SDL_KEYDOWN || event.type == SDL_KEYUP)
{
    // Move centerpoint of rotation for one of the trees:
    if (keyboard_state_array[SDL_SCANCODE_UP] && !(keyboard_state_array[SDL_SCANCODE_DOWN]))
    {
        --location.y;
    }
    else if (!keyboard_state_array[SDL_SCANCODE_UP] && keyboard_state_array[SDL_SCANCODE_DOWN])
    {
        ++location.y;
    }

    if (keyboard_state_array[SDL_SCANCODE_RIGHT] && !keyboard_state_array[SDL_SCANCODE_LEFT])
    {
        ++location.x;
    }
    else if (!keyboard_state_array[SDL_SCANCODE_RIGHT] && keyboard_state_array[SDL_SCANCODE_LEFT])
    {
        --location.x;
    }
}
于 2015-06-04T01:28:47.210 に答える
3

キーダウン イベントだけを見るのではなく、一度に複数のキーを処理するソリューションでは、キーダウン イベントとキーアップ イベントの両方を確認し、問題のキーの状態を追跡する必要があります。

したがって、(疑似コード)の代わりに:

on keydown:
    case left_key:
        object.setMovement(left)
    case forward_key:
        object.setMovement(forward)

代わりに、次のようなものがあります(これも疑似コードです):

on keydown:
    case left_key:
        keystates[left] = true
        object.updateMovement(keystates)
    case forward_key:
        keystates[forward] = true
        object.updateMovement(keystates)

on keyup:
    case left_key:
        keystates[left] = false
        object.updateMovement(keystates)
    case forward_key:
        keystates[forward] = false
        object.updateMovement(keystates)

次に、updateMovementルーチンはkeystatesすべての移動キーの状態に基づいて複合移動を調べ、把握します。

于 2009-08-10T03:22:07.497 に答える
0

SDL_GetKeyStateを使ってキーボードの状態を取得する

于 2009-08-10T03:29:47.980 に答える