熟悉使用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处理键盘,同时支持多个按键等吗?
由于
答案 0 :(得分:17)
答案 1 :(得分:13)
一个好的方法是编写一个键盘(“输入”)处理程序,它将处理输入事件并将事件的状态保持在某种结构中(关联数组听起来很好 - 键[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);
答案 2 :(得分:4)
如果您正在使用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;
}
}
答案 3 :(得分:3)
不仅要查看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
并根据所有移动键的状态计算出复合移动。
答案 4 :(得分:0)
使用SDL_GetKeyState获取键盘状态