一直在使用c ++在Ubuntu上使用SDL来熟悉OpenGL编程。 经过一番环顾四周,我正在开始了解。 我需要使用SDL处理键盘事件的build议。
我有一个第一人称摄像头,可以前后左右移动,并用鼠标四顾四周。 这是我的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; } } }
现在在这个工作中,它有一些限制。 最大的一个,我的问题的目的是,它似乎只处理被按下的最新密钥。 所以,如果我抱着'走路'倒退,按'd'右移,我就会右转,但不能倒退。
有人能指出我正确的方向,以更好的键盘处理与SDL,一次支持多个按键,等等?
谢谢
一个好的方法是编写一个键盘(“输入”)处理程序,它将处理输入事件并将事件的状态保持在某种结构(关联数组听起来很好 – 键[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);
SDL会跟踪所有密钥的当前状态。 您可以通过以下方式访问此状态
SDL_GetKeyState()
所以,每次迭代都可以根据关键状态更新动作。 为了使运动平滑,您应该根据更新之间的时间更新运动幅度。
与其仅仅关注keydown事件,任何要关心多个键的解决方案都将不得不关注keydown和keyup事件,并且要跟踪所讨论的键的状态。
所以,而不是(伪代码):
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
并根据所有移动键的状态一起找出组合移动。
如果您使用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; } }
使用SDL_GetKeyState获取键盘状态