如何使用 SDL 同时处理多个按键?
我需要有关使用 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 进行键盘处理、同时支持多个按键等吗?
I need advice on keyboard event handling with SDL.
I have a 1st person camera, and can walk fwd, back, strafe left and right and use the mouse to look around which is great. Here is my processEvents function:
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;
}
}
}
now while this is working, it has some limitations. The biggest one and the purpose of my question is that it seems to only process the latest key that was pressed. So if I am holding 's' to walk backwards and I press 'd' to strafe right, I end up strafing right but not going backwards.
Can someone point me in the right direction for better keyboard handling with SDL, support for multiple keypresses at once, etc?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
SDL 跟踪所有按键的当前状态。 您可以通过以下方式访问此状态:
SDL_GetKeyState()
因此,每次迭代您都可以更新动作基于关键状态。 为了使运动平滑,您应该根据更新之间经过的时间来更新运动幅度。
SDL keeps track of the current state of all keys. You can access this state via:
SDL_GetKeyState()
So, each iteration you can update the movements based on the key state. To make the movement smooth you should update the movement magnitude based on the time elapsed between updates.
一个好的方法是编写一个键盘(“输入”)处理程序,该处理程序将处理输入事件并将事件的状态保留在某种结构中(关联数组听起来不错 - key[keyCode])。
每次键盘处理程序收到“按键按下”事件时,都会将该按键设置为启用(true),而当收到按键按下事件时,会将其设置为禁用(false)。
然后,您可以一次检查多个键,而无需直接拉取事件,并且您将能够在整个框架中重复使用键盘,而无需将其传递给子例程。
一些快速的伪代码:
A good approach will be to write a keyboard ("input") handler that will process input events and keep the event's state in some sort of a structure (associative array sounds good - key[keyCode]).
Every time the keyboard handler receives a 'key pressed' event, it sets the key as enabled (true) and when it gets a key down event, it sets it as disabled (false).
Then you can check multiple keys at once without pulling events directly, and you will be able to re-use the keyboard across the entire frame without passing it around to subroutines.
Some fast pseudo code:
如果您使用的是 SDL2,请使用
SDL_GetKeyboardState
。例子:
If you're using SDL2 then use
SDL_GetKeyboardState
.Example:
任何要同时关心多个按键的解决方案都必须同时查看 keydown 和 keyup 事件,并跟踪相关按键的状态,而不是仅查看 keydown 事件。
因此,不是(伪代码):
相反,您会得到更像(再次伪代码)的东西:
然后
updateMovement
例程将查看keystates
并根据所有运动键的状态组合在一起。Instead of only looking at keydown events, any solution which is going to be caring about multiple keys at once is going to have to be looking at both keydown and keyup events, and keeping track of the state of the keys in question.
So instead of (pseudocode):
instead you'd have something more like (again pseudocode):
Then the
updateMovement
routine would look atkeystates
and figure out a composite movement based on the states of all movement keys together.使用 SDL_GetKeyState 获取键盘状态
use SDL_GetKeyState to get the keyboard state
我知道以前的答案很好地解决了这个问题,但我想分享我区分任何键的 KeyUp、KeyDown 和 KeyHold 的方法。 我所做的基本上就是将所有按键状态保存在两个名为“上一个”和“当前”的数组中,这样我就可以同时检测按键按下、按下和继续按键。
然后我在游戏循环中使用我的 feed 函数,如下所示:
最后,这是您可以在任何 .cpp 上使用的代码片段来控制按键
GetKeyUp 和 GetKeyDown 也以相同的方式工作。 希望能帮助到你!
I know previous answers adress the issue well but I wanted to share my way which differentiate KeyUp,KeyDown and KeyHold for any key. What I do basically is just holding all keystates in two arrays called Previous and Current so I can detect keydown, up and continues keypress all at once.
Then I use my feed function on game loop like this:
lastly, here is the code snippet that you can use on any .cpp to control key presses
GetKeyUp and GetKeyDown also works the same way. Hope it helps!