I’m having a lot of trouble getting my keyboard input to work the way I want it to. I’m using SDL-1.12.13 and C. Here’s my function for polling the input:
int pressed ()
{
SDL_Event event;
while(SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_KEYDOWN:
switch(event.key.keysym.sym)
{
case SDLK_LEFT:
kleft = 1;
break;
case SDLK_RIGHT:
kright = 1;
break;
case SDLK_UP:
kup = 1;
break;
case SDLK_DOWN:
kdown = 1;
break;
default:
break;
}
break;
case SDL_KEYUP:
switch(event.key.keysym.sym)
{
case SDLK_LEFT:
kleft = 0;
break;
case SDLK_RIGHT:
kright = 0;
break;
case SDLK_UP:
kup = 0;
break;
case SDLK_DOWN:
kdown = 0;
break;
default:
break;
}
break;
}
}
}
Essentially, in my map loop, it calls this function, then increases the character’s X and Y coordinates accordingly based on which variables are equal to 1. My problem is that SDL_KEYUP seems to be triggering on its own! I have to constantly tap the direction keys to continue moving. When I comment the SDL_KEYUP section out, the character will glide across the screen, as expected.
Any ideas what I’m doing wrong? Thanks for taking a look
I tried using SDL_EnableKeyRepeat before the map loop, but it doesn’t seem to do anything. Essentially I placed SDL_EnableKeyRepeat(10,10); right before the loop, but it makes no indication of repeating the key. Am I calling the function in the wrong place or something?
#include <SDL/SDL.h>
char *imagename [17];
int drawx = 0;
int drawy = 0;
int kup = 0;
int kdown = 0;
int kright = 0;
int kleft = 0;
int playerx = 128;
int playery = 128;
int playerxl = 32;
int playeryl = 32;
int pressed ();
int main ( int argc, char** argv )
{
// @note: remember to initialize SDL
// (I wonder why it already works without O_o)
SDL_Init(SDL_INIT_VIDEO);
atexit(SDL_Quit);
SDL_Surface* screen = SDL_SetVideoMode(640, 480, 16,
SDL_HWSURFACE|SDL_DOUBLEBUF);
// @note: load the player sprite ONCE ;)
SDL_Surface* player = SDL_LoadBMP("character.bmp");
SDL_EnableKeyRepeat(10,10);
// @note: you just need that once :)
SDL_ShowCursor(SDL_DISABLE);
int done = 0;
while (done == 0)
{
// @note: remember to clear the screen on each loop
SDL_FillRect(screen, NULL, 0x000000);
// @note: to shutdown when window was close-clicked
if (pressed() == -1) {
done = 1;
break;
}
if (kup == 1)
{
playery += -2;
}
if (kdown == 1)
{
playery += 2;
}
if (kright == 1)
{
playerx += 2;
}
if (kleft == 1)
{
playerx += - 2;
}
/*
if (playery > 0)
if (playery < 480)
if (playerx > 0)
if (playerx < 640)
{
if (playerxl != playerx)
{
playerxl = playerx;
draw (playerx, playery, "character.bmp");
}
if (playeryl != playery)
{
playeryl = playery;
draw (playerx, playery, "character.bmp");
}
}*/
// @note: you should draw on each loop, even the player did not move
SDL_Rect dstrect;
dstrect.x = playerx;
dstrect.y = playery;
SDL_BlitSurface(player, NULL, screen, &dstrect);
SDL_Flip(screen);
if (playerx < 1)
playerx = 1;
if (playerx > 600)
playerx = 600;
if (playery < 1)
playery = 1;
if (playery > 440)
playery = 440;
}
// @note: you player can be free'd at the end
SDL_FreeSurface(player);
// @note: don't forget to shutdown SDL (not needed here but good style)
SDL_Quit();
return 0;
}
int pressed ()
{
SDL_Event event;
while(SDL_PollEvent(&event))
{
switch(event.type)
{
// @note: to shutdown when window was close-clicked
case SDL_QUIT:
return -1;
case SDL_KEYDOWN:
switch(event.key.keysym.sym)
{
case SDLK_LEFT:
kleft = 1;
break;
case SDLK_RIGHT:
kright = 1;
break;
case SDLK_UP:
kup = 1;
break;
case SDLK_DOWN:
kdown = 1;
break;
default:
break;
}
break;
case SDL_KEYUP:
switch(event.key.keysym.sym)
{
case SDLK_LEFT:
kleft = 0;
break;
case SDLK_RIGHT:
kright = 0;
break;
case SDLK_UP:
kup = 0;
break;
case SDLK_DOWN:
kdown = 0;
break;
default:
break;
}
break;
}
}
}
Here are some comments on the code and your problem (they are also in the code at the line with “// @note: […]”:
You should initialize SDL before using SDL-functions. But I wonder why it already works without O_o
In larger programs, loading the image over and over will slowdown performance. A better solution is to load the image in the first place.
You don’t need to disable the cursor on each loop.
The basic game-loop is: Clear Screen; Handle Logic; Render Stuff; Flip Screen; Limit FPS
I added handling SDL_Quit to stop the mainloop on a window close.
As I said: draw on each loop, even the player did not move. Else (if you move another window over your window and move the other one off again) there will be black boxes on your game window until the window is redrawn.
At the end you can free your player’s image’s surface
And you should shutdown SDL. It is not needed here, because the program will terminate and free all stuff; but it’s good style to do SDL_Quit().
I don’t know what your problem was exactly but not it seems to work. The problem might came from the
if (playery > 0)
if (playery < 480)
if (playerx > 0)
if (playerx < 640)
{
if (playerxl != playerx)
{
playerxl = playerx;
draw (playerx, playery, “character.bmp”);
}
if (playeryl != playery)
{
playeryl = playery;
draw (playerx, playery, “character.bmp”);
}
part. Actual you do not need the last player position in this case.
Well… the list (see above) looks quite long and strict… but it’s cool. These are mostly some performance- or style-tips. I hope the code is already easy-to read for you
Thank you so much I have been stuck on this for a while!
Thanks a lot for all the advice too. I’m still in the process of learning a lot, so this really speeds things up and avoids some major problems later on!