ubuntu 如何处理多个按键一次与SDL?

eufgjt7s  于 2024-01-06  发布在  其他
关注(0)|答案(6)|浏览(315)

我需要关于SDL键盘事件处理的建议。
我有一个第一人称相机,可以向前走,向后走,左右扫射,用鼠标环顾四周,这很棒。这是我的processEvents函数:

  1. void processEvents()
  2. {
  3. int mid_x = screen_width >> 1;
  4. int mid_y = screen_height >> 1;
  5. int mpx = event.motion.x;
  6. int mpy = event.motion.y;
  7. float angle_y = 0.0f;
  8. float angle_z = 0.0f;
  9. while(SDL_PollEvent(&event))
  10. {
  11. switch(event.type)
  12. {
  13. case SDL_KEYDOWN:
  14. switch(event.key.keysym.sym)
  15. {
  16. case SDLK_ESCAPE:
  17. quit = true;
  18. break;
  19. case SDLK_w:
  20. objCamera.Move_Camera( CAMERASPEED);
  21. break;
  22. case SDLK_s:
  23. objCamera.Move_Camera(-CAMERASPEED);
  24. break;
  25. case SDLK_d:
  26. objCamera.Strafe_Camera( CAMERASPEED);
  27. break;
  28. case SDLK_a:
  29. objCamera.Strafe_Camera(-CAMERASPEED);
  30. break;
  31. default:
  32. break;
  33. }
  34. break;
  35. case SDL_MOUSEMOTION:
  36. if( (mpx == mid_x) && (mpy == mid_y) ) return;
  37. SDL_WarpMouse(mid_x, mid_y);
  38. // Get the direction from the mouse cursor, set a resonable maneuvering speed
  39. angle_y = (float)( (mid_x - mpx) ) / 1000;
  40. angle_z = (float)( (mid_y - mpy) ) / 1000;
  41. // The higher the value is the faster the camera looks around.
  42. objCamera.mView.y += angle_z * 2;
  43. // limit the rotation around the x-axis
  44. if((objCamera.mView.y - objCamera.mPos.y) > 8) objCamera.mView.y = objCamera.mPos.y + 8;
  45. if((objCamera.mView.y - objCamera.mPos.y) <-8) objCamera.mView.y = objCamera.mPos.y - 8;
  46. objCamera.Rotate_View(-angle_y);
  47. break;
  48. case SDL_QUIT:
  49. quit = true;
  50. break;
  51. case SDL_VIDEORESIZE:
  52. screen = SDL_SetVideoMode( event.resize.w, event.resize.h, screen_bpp, SDL_OPENGL | SDL_HWSURFACE | SDL_RESIZABLE | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE );
  53. screen_width = event.resize.w;
  54. screen_height = event.resize.h;
  55. init_opengl();
  56. std::cout << "Resized to width: " << event.resize.w << " height: " << event.resize.h << std::endl;
  57. break;
  58. default:
  59. break;
  60. }
  61. }
  62. }

字符串
现在,虽然这是工作,它有一些局限性。2最大的一个和我的问题的目的是,它似乎只处理最近被按下的关键。3所以,如果我拿着's'向后走,我按'd'扫射的权利,我最终扫射的权利,但不倒退。
有人能为我指出正确的方向,让我用SDL更好地处理键盘,一次支持多个按键吗?

bz4sfanl

bz4sfanl1#

SDL跟踪所有键的当前状态。您可以通过以下方式访问此状态:
SDL_GetKeyState()
所以,每次迭代你都可以根据关键点状态更新移动。为了使移动平滑,你应该根据更新之间经过的时间更新移动幅度。

72qzrwbm

72qzrwbm2#

一个好的方法是编写一个键盘(“input”)处理程序,它将处理输入事件并将事件的状态保存在某种结构中(关联数组听起来不错- key[keyCode])。
每当键盘处理程序收到一个“keypressed”事件时,它将键设置为启用(true),当它收到一个keydown事件时,它将其设置为禁用(false)。
然后,您可以一次检查多个键,而无需直接提取事件,并且您将能够在整个框架中重用键盘,而无需将其传递给子例程。
一些快速的伪代码:

  1. class KeyboardHandler {
  2. handleKeyboardEvent(SDL Event) {
  3. keyState[event.code] = event.state;
  4. }
  5. bool isPressed(keyCode) {
  6. return (keyState[keyCode] == PRESSED);
  7. }
  8. bool isReleased(keyCode) {
  9. return (keyState[keyCode] == RELEASED);
  10. }
  11. keyState[];
  12. }
  13. ...
  14. while(SDL Pull events)
  15. {
  16. switch(event.type) {
  17. case SDL_KEYDOWN:
  18. case SDL_KEYUP:
  19. keyHandler.handleKeyboardEvent(event);
  20. break;
  21. case SDL_ANOTHER_EVENT:
  22. ...
  23. break;
  24. }
  25. }
  26. // When you need to use it:
  27. if(keyHandler.isPressed(SOME_KEY) && keyHandler.isPressed(SOME_OTHER_KEY))
  28. doStuff(TM);

字符串

展开查看全部
omvjsjqw

omvjsjqw3#

如果您使用的是SDL 2,则使用SDL_GetKeyboardState
范例:

  1. const Uint8 *keyboard_state_array = SDL_GetKeyboardState(NULL);
  2. SDL_PollEvent(&event);
  3. if(event.type == SDL_KEYDOWN || event.type == SDL_KEYUP)
  4. {
  5. // Move centerpoint of rotation for one of the trees:
  6. if (keyboard_state_array[SDL_SCANCODE_UP] && !(keyboard_state_array[SDL_SCANCODE_DOWN]))
  7. {
  8. --location.y;
  9. }
  10. else if (!keyboard_state_array[SDL_SCANCODE_UP] && keyboard_state_array[SDL_SCANCODE_DOWN])
  11. {
  12. ++location.y;
  13. }
  14. if (keyboard_state_array[SDL_SCANCODE_RIGHT] && !keyboard_state_array[SDL_SCANCODE_LEFT])
  15. {
  16. ++location.x;
  17. }
  18. else if (!keyboard_state_array[SDL_SCANCODE_RIGHT] && keyboard_state_array[SDL_SCANCODE_LEFT])
  19. {
  20. --location.x;
  21. }
  22. }

字符串

展开查看全部
ac1kyiln

ac1kyiln4#

而不是只看keydown事件,任何解决方案,这将是关心多个键在一次将不得不看keydown和keyup事件,并保持跟踪的状态键的问题。
因此,代替(pseudocode):

  1. on keydown:
  2. case left_key:
  3. object.setMovement(left)
  4. case forward_key:
  5. object.setMovement(forward)

字符串
相反,你会得到更像(又是伪代码)的东西:

  1. on keydown:
  2. case left_key:
  3. keystates[left] = true
  4. object.updateMovement(keystates)
  5. case forward_key:
  6. keystates[forward] = true
  7. object.updateMovement(keystates)
  8. on keyup:
  9. case left_key:
  10. keystates[left] = false
  11. object.updateMovement(keystates)
  12. case forward_key:
  13. keystates[forward] = false
  14. object.updateMovement(keystates)


然后,updateMovement例程将查看keystates,并根据所有移动键的状态计算出一个复合移动。

展开查看全部
omtl5h9j

omtl5h9j5#

使用SDL_GetKeyState获取键盘状态

nwwlzxa7

nwwlzxa76#

我知道以前的答案很好地解决了这个问题,但我想分享我的方式,区分KeyUp,KeyDown和KeyHold任何键。我所做的基本上是在两个数组中保存所有的键状态,称为Previous和Current,这样我就可以检测到keydown,up并同时继续按键。

  1. #include "smlkr_input_system.h"
  2. SMLKR_InputSystem* InputSys = NULL; /*--- SINGLETON InputSys ---*/
  3. void SMLKR_InputSystem_Init() {
  4. SMLKR_InputSystem* InputSystem = (SMLKR_InputSystem *)malloc(sizeof(SMLKR_InputSystem));
  5. InputSystem->KeyStatesPrevious = (Uint8*)calloc(512,sizeof(Uint8));
  6. InputSystem->KeyStatesCurrent = (Uint8*)calloc(512,sizeof(Uint8));
  7. InputSys = InputSystem;
  8. }
  9. void SMLKR_InputSystem_Feed(SDL_Event* e) {
  10. while (SDL_PollEvent(e)) {
  11. if (e->type == SDL_QUIT) {
  12. break;
  13. }
  14. }
  15. memcpy(InputSys->KeyStatesPrevious,InputSys->KeyStatesCurrent,sizeof(Uint8)*512);
  16. memcpy(InputSys->KeyStatesCurrent,SDL_GetKeyboardState(NULL),sizeof(Uint8)*512);
  17. }
  18. bool SMLKR_InputSystem_GetKeyDown(const SDL_Scancode keycode) {
  19. return InputSys->KeyStatesPrevious[keycode] == 0 && InputSys->KeyStatesCurrent[keycode] == 1;
  20. }
  21. bool SMLKR_InputSystem_GetKeyUp(const SDL_Scancode keycode) {
  22. return InputSys->KeyStatesPrevious[keycode] == 1 && InputSys->KeyStatesCurrent[keycode] == 0;
  23. }
  24. bool SMLKR_InputSystem_GetKey(const SDL_Scancode keycode) {
  25. return InputSys->KeyStatesPrevious[keycode] == 1 && InputSys->KeyStatesCurrent[keycode] == 1;
  26. }

字符串
然后我在game循环中使用feed函数,如下所示:

  1. void SMLKR_Main_GameLoop() {
  2. SDL_Event e;
  3. bool quit = false;
  4. while (!quit) {
  5. SDL_RenderClear(MainRenderer);
  6. SMLKR_InputSystem_Feed(&e);
  7. if(e.type==SDL_QUIT) { quit = true; }
  8. SMLKR_World_Update(Game->World);
  9. SDL_RenderPresent(MainRenderer);
  10. }
  11. }


最后,这里是代码片段,您可以在任何.cpp上使用它来控制按键

  1. if(SMLKR_InputSystem_GetKey(SDL_SCANCODE_LEFT) && SMLKR_InputSystem_GetKey(SDL_SCANCODE_UP)) {
  2. printf("left&up\n");
  3. }


GetKeyUp和GetKeyDown也是以同样的方式工作的。希望对你有帮助!

展开查看全部

相关问题