在 SDL 中输入(按下按键)

问题描述 投票:0回答:4

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

while not KeyHit( KEY_ESC ) 
{
//Code here
}
events input sdl key
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 Keyboard类

  1. 单键输入
  2. 同时组合键(按任意顺序全部按下)
  3. 顺序组合键(按特定顺序按下所有按键)

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


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
投票

您应该有 2 个布尔值表作为键。在一张表中,您可以根据 SDL keydown/keyup 事件将键设置为 true 或 false,而在另一张表中,您可以使用 false 进行初始化。检查 keyPressed 时,只需将第二个表键与第一个表键进行比较,如果不同,如果第二个表键为 false,则它被按下,否则它被释放。之后,您执行 secondaryTable[key] := 而不是 secondaryTable[key]。有效!


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 对象,该对象用作数组键,但它需要整数。

© www.soinside.com 2019 - 2024. All rights reserved.