Как я могу обрабатывать непрерывные ключи с помощью SDL?

Я создал куб в opengl, используя SDL. Теперь я пытаюсь переместить камеру в направлении X, если пользователь нажимает клавиши со стрелками влево или вправо и направление Y, если пользователь нажимает клавиши со стрелками вверх или вниз. Прямо сейчас камера перемещается на фиксированную величину в определенном направлении, если ключ нажимается один раз. Неважно, как долго человек удерживает ключ, он движется только по этой фиксированной сумме. Я хочу, чтобы камера двигалась непрерывно, пока нажата клавиша.

Ниже приведен код для опроса клавиатуры.

        while ( SDL_PollEvent( &event ) )
        {
            switch( event.type )
            {
            case SDL_ACTIVEEVENT:
                if ( event.active.gain == 0 )
                isActive = FALSE;
                else
                isActive = TRUE;
                break;              
            case SDL_VIDEORESIZE:
                surface = SDL_SetVideoMode( event.resize.w,
                            event.resize.h,
                            16, videoFlags );
                if ( !surface )
                {
                    fprintf( stderr, "Could not get a surface after resize: %s\n", SDL_GetError( ) );
                    Quit( 1 );
                }
                resizeWindow( event.resize.w, event.resize.h );
                break;
            case SDL_KEYDOWN:
                handleKeyPress( &event.key.keysym );
                break;
            case SDL_QUIT:
                done = TRUE;
                break;
            default:
                break;
            }
        }

И ниже я упомянул функцию обработчика нажатия клавиш

void handleKeyPress( SDL_keysym *keysym )
{
    switch( (keysym->sym) ){
        case SDLK_ESCAPE:
            Quit(0);
            break;
        case SDLK_LEFT:
              eye[0] -= 0.1;
              break;
            case SDLK_RIGHT:
              eye[0] += 0.1;
              break;
            case SDLK_UP:
              eye[1] -= 0.1;
              break;
            case SDLK_DOWN:
              eye[1] += 0.1;
              break;
            default:
              break;
      }

    return;
}

Какие изменения я должен внести в свой код для обработки непрерывного обнаружения нажатия клавиш?

Примечание: Следующий код выполняет требуемую работу, но я не понимаю, почему

if ( ( SDL_EnableKeyRepeat( 100, SDL_DEFAULT_REPEAT_INTERVAL ) ) )
{
        fprintf( stderr, "Setting keyboard repeat failed: %s\n",
             SDL_GetError( ) );
        Quit( 1 );
}
5 голосов | спросил snape 9 32011vEurope/Moscow11bEurope/MoscowWed, 09 Nov 2011 17:52:10 +0400 2011, 17:52:10

4 ответа


12
void Main::processInput()
{
    Uint8* keystate = SDL_GetKeyState(NULL);

    //continuous-response keys
    if(keystate[SDLK_LEFT])
    {
    }
    if(keystate[SDLK_RIGHT])
    {
    }
    if(keystate[SDLK_UP])
    {
    }
    if(keystate[SDLK_DOWN])
    {
    }

    //single-hit keys, mouse, and other general SDL events (eg. windowing)
    while(SDL_PollEvent(&event))
    {
        switch (event.type)
        {
            case SDL_MOUSEMOTION:
            break;

            case SDL_QUIT:
            case SDL_KEYDOWN:
                if(event.key.keysym.sym == SDLK_ESCAPE)
                    done = true; //quit
            break;
        }
    }
}

Использование:

Main::Main()
{
    //set up SDL etc.
    //set up timing variables etc.
    timeStepMs = 1000.f / yourUpdateFrequency; //eg. 30Hz
    //set up game world etc.

    //main loop, run like the wind!
    while(!done)
    {

        timeLastMs = timeCurrentMs;
        timeCurrentMs = SDL_GetTicks();
        timeDeltaMs = timeCurrentMs - timeLastMs;
        timeAccumulatedMs += timeDeltaMs;

        while (timeAccumulatedMs >= timeStepMs)
        {
              processInput();
              //update world: do ai, physics, etc. here
              timeAccumulatedMs -= timeStepMs;
        }
        render(); //render update only once
    }
}
ответил Arcane Engineer 9 32011vEurope/Moscow11bEurope/MoscowWed, 09 Nov 2011 21:22:09 +0400 2011, 21:22:09
2

Если вы используете SDL версию 1.x, используйте SDL_GetKeyState () , чтобы определить, находится ли ключ вверх или вниз.

Если вы используете SDL версии 2.x, используйте SDL_GetKeyboardState () , чтобы определить, ключ вверх или вниз.

ответил Kylotan 9 32011vEurope/Moscow11bEurope/MoscowWed, 09 Nov 2011 20:11:58 +0400 2011, 20:11:58
1

Я не знаю точно, как это сделать в SDL, но в псевдокоде это подход

bool[] isKeyDown
bool[] isKeyPressed

public void Check(){
    foreach Key k in Keys
        if(k.isDown && !isKeyDown[k]){
               isKeyDown[k] = true;
               isKeyPressed[k] = true;
        }        
        else if(k.IsDown && isKeyDown[k]){
            isKeyPressed[k] = false;
        }    
        else{
            isKeyDown[k] = false;
            isKeyPressed[k] = false;
        }
    }
}     

Этот способ isKeyPressed [k] истинен и только true при первом нажатии k, вы можете использовать его для навигации по меню. Альтернативно isKeyDown [k] истинно все время, когда k было нажато.

Теперь я уверен, что SDL имеет способ запросить текущее состояние ключа, но если вы можете только repsond на события, вы просто очистите isKeyPressed [k] в начале каждого игрового цикла, сделайте isKeyPressed [k] и isKeyDown [k] true для каждого события KeyDown и сделать isKeyDown [k] false для каждого события KeyUp.

ответил Roy T. 9 32011vEurope/Moscow11bEurope/MoscowWed, 09 Nov 2011 18:01:07 +0400 2011, 18:01:07
1

Вам понадобится прочитать SDL_KEYUP и SDL_KEYDOWN. Вы можете либо иметь его, чтобы он задавал логическое значение true, когда нажата клавиша, и false, когда ключ не нажат, а затем он проверяет логические значения и выполняет действие, если true, или вы можете сделать что-то вроде этого ...

if(SDL_PollEvent(&event)) {
    if(event.type==SDL_KEYDOWN) {
        switch(event.key.keysym.sym) {
            case SDLK_UP:    yVel-=2; break;
            case SDLK_DOWN:  yVel+=2; break;
            case SDLK_LEFT:  xVel-=2; break;
            case SDLK_RIGHT: xVel+=2; break;
        }
    }
    if(event.type==SDL_KEYUP) {
        switch(event.key.keysym.sym) {
            case SDLK_UP:    yVel+=2; break;
            case SDLK_DOWN:  yVel-=2; break;
            case SDLK_LEFT:  xVel+=2; break;
            case SDLK_RIGHT: xVel-=2; break;
        }
    }
}

И затем просто добавьте x /yVel в позицию x /y того, что вы хотите переместить ...

x+=xVel;
y+=yVel;
ответил rzrscm 12 Jam1000000amSat, 12 Jan 2013 11:01:23 +040013 2013, 11:01:23

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132