SDL中的输入(按键按下时)

10

我想知道在SDL的while循环中如何检测按键或释放键。我知道你可以使用SDL获取事件,例如OnKeyPressed、OnKeyReleased、OnKeyHit等,但我想知道如何构建像返回布尔值的'KeyPressed'函数,而不是一个事件。例如:

while not KeyHit( KEY_ESC ) 
{
//Code here
}
4个回答

21

我知道你已经选择了一个答案.. 但是这里是我通常使用一个数组来完成的实际代码。 :)

首先在某个地方定义这个。

bool KEYS[322];  // 322 is the number of SDLK_DOWN events

for(int i = 0; i < 322; i++) { // init them all to false
   KEYS[i] = false;
}

SDL_EnableKeyRepeat(0,0); // you can configure this how you want, but it makes it nice for when you want to register a key continuously being held down

稍后,创建一个keyboard()函数,用于注册键盘输入。
void keyboard() {
        // message processing loop
        SDL_Event event;
        while (SDL_PollEvent(&event)) {
            // check for messages
            switch (event.type) {
                // exit if the window is closed
            case SDL_QUIT:
                game_state = 0; // set game state to done,(do what you want here)
                break;
                // check for keypresses
            case SDL_KEYDOWN:
                KEYS[event.key.keysym.sym] = true;
                break;
            case SDL_KEYUP:
                KEYS[event.key.keysym.sym] = false;
                break;
            default:
                break;
            }
        } // end of message processing
}

当你想要使用键盘输入,比如一个handleInput()函数时,它可能看起来像这样:

void handleInput() {
    if(KEYS[SDLK_LEFT]) { // move left
        if(player->x - player->speed >= 0) {
            player->x -= player->speed;
        }
    }
    if(KEYS[SDLK_RIGHT]) { // move right
        if(player->x + player->speed <= screen->w) {
            player->x += player->speed;
        }
    }
    if(KEYS[SDLK_UP]) { // move up
        if(player->y - player->speed >= 0) {
            player->y -= player->speed;
        }
    }
    if(KEYS[SDLK_DOWN]) { // move down
        if(player->y + player->speed <= screen->h) {
            player->y += player->speed;
        }
    }
    if(KEYS[SDLK_s]) { // shoot 
        if(SDL_GetTicks() - player->lastShot > player->shotDelay) {
            shootbeam(player->beam);
        }
    }
    if(KEYS[SDLK_q]) {
        if(player->beam == PLAYER_BEAM_CHARGE) {
            player->beam = PLAYER_BEAM_NORMAL;
        } else {
            player->beam = PLAYER_BEAM_CHARGE;
        }
    }
    if(KEYS[SDLK_r]) {
        reset();
    }

    if(KEYS[SDLK_ESCAPE]) {
        gamestate = 0;
    }
}

当然,您可以轻松地做您想做的事情。

while(KEYS[SDLK_s]) {
    // do something
    keyboard(); // don't forget to redetect which keys are being pressed!
}

我网站上有更新版本:

为了避免发布大量源代码,您可以查看完整的C++ SDL键盘类,支持以下功能:

  1. 单键输入
  2. 同时按下多个键(任意顺序按下的键)
  3. 按特定顺序按下的多个键

http://kennycason.com/posts/2009-09-20-sdl-simple-space-shooter-game-demo-part-i.html(如果您有任何问题,请告诉我)


1
存在一个SDL函数,它恰好实现了你提出的内容(也许你的回答已经过时了,因为是2010年的?)。请看一下我的回答。 - Anonymous

8
这里有一个SDL函数可以实现此功能:SDL_GetKeyboardState 以下是检查左右CTRL键是否被按下的示例代码:
      const Uint8* state = SDL_GetKeyboardState(nullptr);

      if (state[SDL_SCANCODE_LCTRL] || state[SDL_SCANCODE_RCTRL]) {
           std::cerr << "ctrl pressed" << std::endl;
      }

1
我在使用LuaJIT的FFI时遇到了问题,以下是我的解决方法:
全局变量:
KEYS = {}

事件代码:
ev = ffi.new("SDL_Event[1]")
function event()
    while sdl.SDL_PollEvent(ev) ~= 0 do
        local e = ev[0]
        local etype = e.type
        if etype == sdl.SDL_QUIT then
            return false -- quit
            -- os.exit() -- prevents interactive mode
        elseif etype == sdl.SDL_KEYDOWN then
            if e.key.keysym.sym == sdl.SDLK_ESCAPE then
                return false -- quit
                -- os.exit()
            end
            print("Pressed: ", e.key.keysym.scancode, "\n")
            KEYS[tonumber(e.key.keysym.sym)] = true
            -- print("Pressed: ", (e.key.keysym.sym == sdl.SDLK_w), "\n");
        elseif etype == sdl.SDL_KEYUP then
            KEYS[tonumber(e.key.keysym.sym)] = false
        elseif etype == sdl.SDL_VIDEORESIZE then
            -- print("video resize W:".. e.resize.w .. " H:" .. e.resize.h)
            width = e.resize.w
            height = e.resize.h
            onResize()
        end
    end
    return true -- everything ok
end

更新函数:
if KEYS[sdl.SDLK_w] == true then
    rot = rot + 1
end

我浪费了大部分时间在这个问题上:

KEYS[tonumber(e.key.keysym.sym)] = false

因为FFI返回的是一个CData对象,它被用作数组键,但它需要整数。

1
你应该有2个布尔型键表。一个表,根据SDL的keydown/keyup事件设置键为true或false,另一个表则初始化为false。在检查keyPressed时,只需将第二个表键与第一个表键进行比较,如果不同,则如果第二个表键为false,则表示它被按下,否则它被释放。之后,你需要执行secondTable[key] := not secondTable[key]。完美!

非常感谢你,我不知道如何表达对你的帮助之感激! - deluvas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接