Inputs in SDL (on key pressed)

2019-04-09 03:16发布

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
}

3条回答
虎瘦雄心在
2楼-- · 2019-04-09 03:38

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!

查看更多
来,给爷笑一个
3楼-- · 2019-04-09 03:40

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.

查看更多
甜甜的少女心
4楼-- · 2019-04-09 03:44

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)

查看更多
登录 后发表回答