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

发布于 2024-09-24 03:14:28 字数 218 浏览 2 评论 0原文

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

while not KeyHit( KEY_ESC ) 
{
//Code here
}

I would like to know how can I detect the press of a key or release of a key in a while loop in SDL. Now, I know you can get the events with SDL like OnKeyPressed, OnKeyReleased, OnKeyHit, etc, but I want to know how to build functions like 'KeyPressed' that returns a boolean, instead of being an event. Example:

while not KeyHit( KEY_ESC ) 
{
//Code here
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

此刻的回忆 2024-10-01 03:14:28

我知道您已经选择了一个答案..但这里有一些实际代码,说明我通常如何使用一个数组来做到这一点。 :)

首先在某处定义它。

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. 顺序按键组合(按特定顺序按下的按键)

< a href="http://kennycason.com/posts/2009-09-20-sdl-simple-space-shooter-game-demo-part-i.html" rel="nofollow noreferrer">http://kennycason .com/posts/2009-09-20-sdl-simple-space-shooter-game-demo-part-i.html(如果您有任何问题,请告诉我)

I know you have already selected an answer.. but here is some actual code of how I typically do it with one array. :)

first define this somewhere.

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

Then later, create a keyboard() function which will register keyboard input

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
}

Then when you actually want to use the keyboard input i.e. a handleInput() function, it may look something like this:

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;
    }
}

And of course you can easily do what you're wanting to do

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

**Updated version on my website: **
For the sake of not posting a lot of source code, you can view a complete SDL Keyboard class in C++ that supports

  1. Single Key Input
  2. Simultaneous Key Combos (Keys all pressed in any order)
  3. Sequential Key Combonations (Keys all pressed in specific order)

http://kennycason.com/posts/2009-09-20-sdl-simple-space-shooter-game-demo-part-i.html (if you have any problems, let me know)

聽兲甴掵 2024-10-01 03:14:28

为此有一个 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;
}

There is an SDL function for this: SDL_GetKeyboardState

Example to check whether left or right CTRL key is pressed:

const Uint8* state = SDL_GetKeyboardState(nullptr);

if (state[SDL_SCANCODE_LCTRL] || state[SDL_SCANCODE_RCTRL]) {
     std::cerr << "ctrl pressed" << std::endl;
}
杀手六號 2024-10-01 03:14:28

我在使用 FFI 的 LuaJIT 中遇到了这个问题,这就是我解决它的方法:

全局:

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

I had this problem in LuaJIT with FFI, this is how I solved it:

Global:

KEYS = {}

Event code:

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

Update function:

if KEYS[sdl.SDLK_w] == true then
    rot = rot + 1
end

Most time i wasted on this:

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

Because FFI is returning a CData object, which was used as the array-key, but it needs the integer.

心碎的声音 2024-10-01 03:14:28

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

You should have 2 tables of booleans for keys. One table, in which you set keys true or false based on the SDL keydown/keyup events, and another one, that you initialize with false. When checking keyPressed, you just compare the second table key with the first table key, and if different, if second table key is false, then it was pressed, else it was released. After that, you do secondTable[key] := not secondTable[key]. Works!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文