2009-08-10 14 views
9

zapoznałem się z programowaniem OpenGL przy użyciu SDL na Ubuntu przy użyciu C++. Po rozejrzeniu się i eksperymentowaniu zaczynam rozumieć. Potrzebuję porady dotyczącej obsługi zdarzeń klawiatury przy użyciu SDL.Jak obsługiwać wiele naciśnięć klawiszy jednocześnie za pomocą SDL?

Posiadam kamerę 1-osobową i mogę przejść fwd, z powrotem, wystrzelić w lewo i prawo i używać myszy do rozglądania się, co jest świetne. Oto moja funkcja 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; 
    } 
} 
} 

teraz, gdy to działa, ma pewne ograniczenia. Największym i moim celem jest to, że wydaje się, że przetwarza tylko najnowszy klucz, który został naciśnięty. Więc jeśli trzymam 's', aby odejść do tyłu i naciskam "d", aby ostro strzelać, kończę ostrzał prosto, ale nie cofam się.

Czy ktoś może wskazać mi właściwy kierunek dla lepszej obsługi klawiatury przy użyciu SDL, obsługi wielu naciśnięć klawiszy itp.?

Dzięki

Odpowiedz

12

Dobrym podejściem będzie napisanie obsługi klawiatury ("wejścia"), która będzie przetwarzać zdarzenia wejściowe i utrzymywać stan wydarzenia w jakiejś strukturze (tablica asocjacyjna brzmi dobrze - klawisz [keyCode]).

Za każdym razem, gdy program obsługi klawiatury odbierze zdarzenie naciśnięcia klawisza, ustawia klucz jako włączony (true), a po otrzymaniu zdarzenia wyłączenia klawisza ustawia go jako wyłączony (fałsz).

Następnie można sprawdzić wiele kluczy naraz bez ciągnięcia zdarzeń bezpośrednio, a będziesz mógł ponownie używać klawiatury w całej ramce bez przekazywania jej do podprogramów.

Niektórzy szybko pseudokod:

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

Naprawdę ładne rozwiązanie to może być stosowane w prawie wszystkich swoich gier – devsaw

3

Zamiast tylko patrząc na keyDown zdarzeń, każde rozwiązanie, które ma być dbanie o wielu klawiszy naraz będzie musiał patrzeć na obu imprezach keyDown i keyUp i śledzenie stanu tych kluczy.

Więc zamiast (pseudokod):

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

zamiast chcesz mieć coś bardziej jak (ponownie Pseudokod):

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) 

Następnie procedura updateMovement wyglądałby na keystates i dowiedzieć się złożony ruch oparty na stanach wszystkich kluczy ruchu razem.

16

SDL śledzi bieżący stan wszystkich kluczy. Możesz uzyskać dostęp do tego stanu poprzez:

SDL_GetKeyState()

Więc każda iteracja można zaktualizować ruchy oparte na stan klucza. Aby ruch był płynny, należy zaktualizować wielkość ruchu w oparciu o czas, jaki upłynął między aktualizacjami.

3

Jeśli używasz SDL2 następnie użyć SDL_GetKeyboardState.

Przykład:

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; 
    } 
} 
Powiązane problemy