C++ 如何使用 SDL 一次处理多个按键?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1252976/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to handle multiple keypresses at once with SDL?
提问by Tim
been getting myself familiar with OpenGL programming using SDL on Ubuntu using c++. After some looking around and experimenting I am starting to understand. I need advice on keyboard event handling with SDL.
一直在使用 C++ 在 Ubuntu 上使用 SDL 熟悉 OpenGL 编程。经过一番环顾和试验后,我开始明白了。我需要有关使用 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:
我有一个第一人称相机,可以向前、向后、向左和向右扫射并使用鼠标环顾四周,这很棒。这是我的 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;
}
}
}
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.
现在虽然这是有效的,但它有一些限制。我的问题最大的一个和目的是它似乎只处理按下的最新键。因此,如果我按住 's' 向后走,然后按 'd' 向右扫射,我最终会向右扫射但不会向后走。
Can someone point me in the right direction for better keyboard handling with SDL, support for multiple keypresses at once, etc?
有人可以为我指出正确的方向,以便使用 SDL 更好地处理键盘,同时支持多个按键等吗?
Thanks
谢谢
回答by Karl Voigtland
SDL keeps track of the current state of all keys. You can access this state via:
SDL 会跟踪所有密钥的当前状态。您可以通过以下方式访问此状态:
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.
因此,每次迭代您都可以根据关键状态更新动作。为了使运动平稳,您应该根据更新之间经过的时间更新运动幅度。
回答by LiraNuna
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]).
一个好的方法是编写一个键盘(“输入”)处理程序来处理输入事件并将事件的状态保持在某种结构中(关联数组听起来不错 - 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).
每次键盘处理程序接收到“按键按下”事件时,它都会将该键设置为启用 (true),当它收到按键按下事件时,它会将其设置为禁用 (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:
一些快速的伪代码:
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);
回答by Grahf
If you're using SDL2 then use SDL_GetKeyboardState
.
如果您使用的是 SDL2,则使用SDL_GetKeyboardState
.
Example:
例子:
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;
}
}
回答by Amber
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.
不是只查看 keydown 事件,任何将同时关注多个键的解决方案都必须同时查看 keydown 和 keyup 事件,并跟踪相关键的状态。
So instead of (pseudocode):
所以而不是(伪代码):
on keydown:
case left_key:
object.setMovement(left)
case forward_key:
object.setMovement(forward)
instead you'd have something more like (again pseudocode):
相反,你会有更像(再次伪代码)的东西:
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)
Then the updateMovement
routine would look at keystates
and figure out a composite movement based on the states of all movement keys together.
然后,该updateMovement
例程将查看keystates
并根据所有运动键的状态一起计算出复合运动。
回答by hiena
use SDL_GetKeyStateto get the keyboard state
使用SDL_GetKeyState获取键盘状态