C++ & SDL: SDL event repeats endlessly - c++

I have this code which is a part of a simple SDL-based game:
SDL_PollEvent(&event);
switch (event.type){
case SDL_QUIT:
quit = true;
break;
case SDL_KEYDOWN: //Det här är för när en knapp trycks ner...
switch (event.key.keysym.sym){
case SDLK_RIGHT:
player1.x_vel = 5.5;
std::cout<<"OOOO\n";
break;
case SDLK_DOWN:
player2_sprite.src.x = 58;
break;
}
break;
case SDL_KEYUP: //Det här är för när en knapp släpps upp..
switch (event.key.keysym.sym){
case SDLK_UP:
std::cout<<"haaaaa\n";
if(player1.canJump){
player1.y_vel = -7.5;
player1.canJump = false;
}
break;
case SDLK_DOWN:
std::cout<<"BBBB\n";
player2_sprite.src.x = 0;
break;
}
break;
}
Now, upon the release of the UP or DOWN arrow key, the release-event keeps triggering forever until any other event is handled. What am I doing wrong here?

You should be checking the return value of SDL_PollEvent. It returns 1 if there is an event to handle, and 0 if there is not. Normally, you handle events in a loop like this (copied from the documentation here):
while (1) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
// handle your event here
}
// do some other stuff here -- draw your app, etc.
}
What is probably happening in your case, is you are handling the event even when SDL_PollEvent returns 0. The event object is left unmodified in that case, so you keep handling the most recent event over and over.

Related

SDL cannot read input from keyboard

I am having trouble dealing with input from the keyboard. Somehow all the letter ones are extremely slow(always a big delay), most of the time it just doesn't load at all. But the up down left right and number keys all work really well. Does anyone know why?
This is my program:
while (!quit)
{
while (SDL_PollEvent(&e) != 0 )
{
SDL_StartTextInput();
//User requests quit
switch (e.type) {
case SDL_QUIT:
quit = true;
break;
case SDL_TEXTINPUT:
if (e.key.keysym.sym == SDLK_w)
std::cout << "w ";
break;
case SDL_KEYDOWN:
if (e.key.keysym.sym == SDLK_1)
std::cout << "1 ";
break;
}
As already mentioned in your comments, you never check the event type.
event.type can be SDL_TEXTINPUT or SDL_KEYDOWN for example.
Here I have a typical event loop copied from one of my projects:
while (SDL_PollEvent(&event)) {
SDL_StartTextInput();
switch (event.type) {
case SDL_QUIT:
appRunning = false;
break;
case SDL_TEXTINPUT:
// here you can use event.text.text; to
break;
case SDL_KEYDOWN:
char keyDown = event.key.keysym.scancode;
break;
}
}
Here is the official list of SDL_Events: https://wiki.libsdl.org/SDL2/SDL_Event
SDL provides event handlers for keyboard input.
SDL_Event e;
.
.
/* Poll for events. SDL_PollEvent() returns 0 when there are no */
/* more events on the event queue, our while loop will exit when */
/* that occurs. */
while(SDL_PollEvent(&e)){
/* We are only worried about SDL_KEYDOWN and SDL_KEYUP events */
switch(event.type){
case SDL_KEYDOWN:
//Keypress
break;
case SDL_KEYUP:
//Key Release
break;
default:
break;
}
Then, you can get the value of key->keysym.sym for the keyboard input.

Open GL SDL Keypresses and behaviours mismatched on program start

I'm developing a simple game in OpenGL and using the SDL library to handle my input.
The game uses several keyboard buttons for input. Two arrow keys, the space bar, the 'r' button to reset the game and escape to close it.
What's currently happening is that the output or the methods being called when these buttons are pressed when I first launch the game are mismatched. (i.e left arrow performs the right arrow's method). This random behaviour ends once I press each of the buttons the game uses apart from the escape button once.
I'm wondering if there is something I'm missing as it feels like I have to 'assign' each button on each launch of the game. I've provided my input handling code below.
if (e.type == SDL_KEYDOWN) {
switch (e.key.keysym.sym) {
case SDLK_ESCAPE:
m_isClosed = true;
break;
case SDLK_SPACE:
m_selection = true;
break;
case SDLK_LEFT:
m_leftPressed = true;
break;
case SDLK_RIGHT:
m_rightPressed = true;
break;
case SDLK_r:
m_reset = true;
break;
}
}
if(e.type == SDL_KEYUP)
switch (e.key.keysym.sym)
{
case SDLK_LEFT:
m_leftPressed = false;
m_keydown = false;
break;
case SDLK_RIGHT:
m_rightPressed = false;
m_keydown = false;
break;
case SDLK_SPACE:
m_selection = false;
m_keydown = false;
break;
case SDLK_r:
m_reset = false;
m_keydown = false;
break;
}
}
Each event handler simply sets a boolean used for the game logic in another class. If you think you need to see anymore code in order to help me let me know.
It turns out that I had not initialised the booleans corresponding to the button listeners to false. A silly mistake but I thought I should provide the solution nonetheless.

SDL Smoother movement in game

I have got a small problem with my game.
It is not a big deal but I'd love to sort this out.
So this is my input processing function:
void MainGame::processInput()
{
SDL_Event evnt;
while (SDL_PollEvent(&evnt)) {
switch (evnt.type) {
case SDL_QUIT:
_gameState = GameState::EXIT;
break;
case SDL_MOUSEMOTION:
break;
case SDL_KEYDOWN:
switch (evnt.key.keysym.sym) {
case SDLK_RIGHT:
player.movePlayer(1);
break;
case SDLK_LEFT:
player.movePlayer(2);
break;
}
}
}
}
and it works just fine, but as you can probably imagine, when I press an arrow key, it moves once (calls the player.movePlayer(); function once) then pauses for a fraction of a second and then continues to read input.
I don't really know how to word it but I hope you know what I mean.
You can also see this effect when you hold any letter in word.
Let's say you press W, it will display the first W instantly and then remaining ones after a fraction of a second something like that:
w wwwwwwwwwwwwwwwwwwwww
I really don't know how to explain it.
So the question is, is there a way to read the raw input from the keyboard so the function will be called continuously straight away?
I often use code like this:
bool keyboard[1<<30]; // EDIT: as noted in the comments this code might not be the most efficient
and in the event loop
while (SDL_PollEvent(&evnt)) {
switch (evnt.type) {
case SDL_QUIT:
_gameState = GameState::EXIT;
break;
case SDL_MOUSEMOTION:
break;
case SDL_KEYDOWN:
keyboard[evnt.key.keysym.sym] = true;
break;
case SDL_KEYUP:
keyboard[evnt.key.keysym.sym] = false;
break;
}
step();
}
and the step function:
void step() {
if(keyboard[SDLK_RIGHT]) player.movePlayer(1);
else if(keyboard[SDLK_LEFT]) player.movePlayer(2);
}

SDL 2.0.3 event loop doesn't work

I can't make SDL wait for a an event. When I try to the window just briefly flashes on my screen and then disappears, I don't get any errors or anything in my IDE, nothing in the build log either. I looked at lazyfoo and the SDL wiki, but no help. I'm using Code blocks and SDL 2.0.3 Here's what I have so far:
while(&event != NULL && !quit)
{
while(SDL_PollEvent(&event) > 0)
{
if(event.type == SDL_QUIT)
{
quit = true;
}
else
{
if(event.type == SDL_KEYDOWN)
{
switch(event.key.keysym.sym)
{
case SDLK_LEFT:
currentSurface = keyPressSurfaces[KEY_PRESS_LEFT];
break;
case SDLK_UP:
currentSurface = keyPressSurfaces[KEY_PRESS_UP];
break;
case SDLK_RIGHT:
currentSurface = keyPressSurfaces[KEY_PRESS_RIGHT];
break;
case SDLK_DOWN:
currentSurface = keyPressSurfaces[KEY_PRESS_DOWN];
break;
default:
currentSurface = keyPressSurfaces[KEY_PRESS_DEFAULT];
break;
}
}
}
}
}
Any suggestions?
you are polling for an event SDL_PollEvent, if you want to wait for an event, you should use SDL_WaitEvent
First, is quit false before you enter this loop?
If there are no events to poll, I believe event is NULL, causing your program to exit the next time it sees while(&event != NULL && !quit). If there are no immediate events on startup, you might not ever make it into that loop. Edit: Whoops - thought event was a pointer:
The while (SDL_PollEvent(&event)) line will loop through until all pending events have been handled. The outter while (!quit) would then keep your program open even if there are no events to process at the moment.

SDL 2.0 Key repeat and delay

I'm having a problem with SDL 2.0 keyboard input in pong-like game. When I order to move to the left by pressing left arrow, it is processed by SDL_PollEvents() and responds correctly if the key was pressed once. However, if I keep the key pressed, I get a short delay (as long as Windows key repeat delay) before moving continuously.
Here is function processing events:
void Event::PlayerEvent (Player &player)
{
while (SDL_PollEvent (&mainEvent))
{
switch (mainEvent.type)
{
case SDL_KEYDOWN :
switch (mainEvent.key.keysym.sym)
{
case SDLK_ESCAPE :
gameRunning = false;
break;
case SDLK_LEFT :
player.moving = player.left;
break;
case SDLK_RIGHT :
player.moving = player.right;
}
break;
case SDL_QUIT :
gameRunning = false;
}
}
}
EDIT: After all, I managed to fix this issue by calling
SystemParametersInfo (SPI_SETKEYBOARDDELAY, 0, 0, 0) at the start of the program and SystemParametersInfo (SPI_SETKEYBOARDDELAY, 1, 0, 0) at the end, to return to standard key repeat delay.
For game movement, you would typically not use events, but rather use states.
Try using SDL_GetKeyboardState() outside of the event loop:
const Uint8* keystates = SDL_GetKeyboardState(NULL);
...
if(keystates[SDL_SCANCODE_LEFT])
player.moving = player.left;
else if(keystates[SDL_SCANCODE_RIGHT])
player.moving = player.right;
using SPI_SETKEYBOARDDELAY is not a good approach. This way your game will not be protable anymore since its only available on Windows.
Instead you should use like menthiond in an answer before SDL_GetKeyboardState.
Howeve be aware that you still have to collect the SDL_PollEvent. Otherwise SDL_GetKeyboardState will be always empty.
So it should be like this:
//...
SDL_Event sdlEvent;
while (SDL_PollEvent(&sdlEvent)) {
if (sdlEvent.type == SDL_QUIT) {
//..
}
}
const Uint8* keystates = SDL_GetKeyboardState(NULL);
if(keystates[SDL_SCANCODE_LEFT]) {
//...
}
if(keystates[SDL_SCANCODE_RIGHT]) {
/...
}
//...
simple as that
int vertical = 0;
int horizontal = 0;
float x = 500;
float y = 500;
float speed = 5.0;
in your sdl loop:
if (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_KEYDOWN:
{
switch (event.key.keysym.sym)
{
case SDLK_LEFT: horizontal=-1; break;
case SDLK_RIGHT: horizontal = 1; break;
case SDLK_UP: vertical=-1; break;
case SDLK_DOWN: vertical=+1; break;
}
break;
}
case SDL_KEYUP:
{
switch (event.key.keysym.sym)
{
case SDLK_LEFT: horizontal = 0; break;
case SDLK_RIGHT: horizontal = 0; break;
case SDLK_UP: vertical = 0; break;
case SDLK_DOWN: vertical = 0; break;
}
break;
}
}
}
x += horizontal * speed;
y += vertical * speed;
Use the SDL_GetKeyboardState capturing outside of - while (SDL_PollEvent (&mainEvent)), that works fine.