2009-08-10 15 views
9

mi sono familiarizzato con la programmazione OpenGL usando SDL su Ubuntu usando C++. Dopo essermi guardato intorno e sperimentato, sto iniziando a capire. Ho bisogno di consigli sulla gestione degli eventi da tastiera con SDL.Come gestire più pressioni di tasti contemporaneamente con SDL?

Ho una macchina fotografica in prima persona, e posso camminare in avanti, indietro, sfilare a destra e sinistra e usare il mouse per guardarmi intorno che è fantastico. Qui è la mia funzione 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; 
    } 
} 
} 

Ora, mentre questo è in funzione, ha alcune limitazioni. Il più grande e lo scopo della mia domanda è che sembra elaborare solo l'ultima chiave che è stata premuta. Quindi se sto trattenendo 's' per camminare all'indietro e premo 'd' per muovere a destra, finisco per mitragliare a destra ma non andare indietro.

Qualcuno può indicarmi la giusta direzione per una migliore gestione della tastiera con SDL, supporto per più pressioni di tasti contemporaneamente, ecc.?

Grazie

risposta

12

Un buon approccio sarà quello di scrivere un gestore di tastiera ("input") che elaborerà gli eventi di input e manterrà lo stato dell'evento in una sorta di struttura (l'array associativo suona bene - key [keyCode]).

Ogni volta che il gestore della tastiera riceve un evento "premuto dalla chiave", imposta la chiave come abilitata (true) e quando riceve un evento key down, la imposta come disabilitata (false).

Quindi è possibile controllare più tasti contemporaneamente senza eseguire direttamente gli eventi e sarà possibile riutilizzare la tastiera su tutto il fotogramma senza passarlo alle subroutine.

Alcuni pseudo codice veloce:

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); 
+0

Davvero una bella soluzione, questo può essere utilizzato in quasi tutti i giochi – devsaw

3

Invece di guardare solo in occasione di eventi KeyDown, qualsiasi soluzione che sta per essere preoccuparsi più tasti contemporaneamente sta andando ad avere per essere alla ricerca di entrambi gli eventi KeyDown e KeyUp, e tenere traccia dello stato delle chiavi in ​​questione.

Così, invece di (pseudo):

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

invece si avrebbe qualcosa di più simile (di nuovo pseudocodice):

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) 

L'esame di routine updateMovement avrebbe guardato keystates e capire un movimento composito basato sugli stati di tutti i tasti di movimento insieme.

16

SDL tiene traccia dello stato corrente di tutti i tasti. È possibile accedere a questo stato tramite:

SDL_GetKeyState()

Così, ogni iterazione è possibile aggiornare i movimenti in base allo stato chiave. Per rendere il movimento fluido, è necessario aggiornare l'entità del movimento in base al tempo trascorso tra gli aggiornamenti.

3

Se stai usando SDL2 quindi utilizzare SDL_GetKeyboardState.

Esempio:

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; 
    } 
} 
Problemi correlati