Texture drawn at wrong coordinates? - c++

I tried drawing a '1' texture at mouse coordinates when I press the 1 key:
switch (e.type)
{
case SDL_QUIT:
{
quit = true;
break;
}
case SDL_KEYDOWN:
{
switch (e.key.keysym.sym)
{
case SDLK_1:
{
SDL_Rect rect = {e.motion.x - 8, e.motion.y - 8, 16, 16};
SDL_RenderCopy(gRenderer, gT[3], NULL, &rect);
printf("1\n");
break;
}
}
break;
}
}
I cannot comprehend why this doesn't work.
gT[3] is the texture of the '1'.
I thought maybe it is because its e.key.keysym.sym but I'm not sure.

SDL_Event::motion is only valid when SDL_Event::type is SDL_MOUSEMOTION.
Stop trying to use SDL_Event::motion when SDL_Event::type is SDL_KEYDOWN, perhaps by recording the X and Y coordinates of the most recent SDL_MOUSEMOTION event and using those instead.

Related

How to draw texture at mouse coords using keyboard

Its like the title suggests, i want to draw a "1" texture at mouse coords using a keyboard key press.
I am using switch statements for input:
switch (e.type)
{
case SDL_QUIT:
{
quit = true;
break;
}
case SDL_MOUSEBUTTONDOWN:
{
switch (e.button.button)
{
case SDL_BUTTON_LEFT:
{
SDL_Rect rect = {e.motion.x - 10, e.motion.y - 10, 20, 20};
SDL_RenderCopy(gRenderer, gT[0], NULL, &rect);
printf("nod\n");
break;
}
}
break;
}
case SDL_KEYDOWN:
{
switch (e.key.keysym.sym)
{
case SDLK_c:
{
SDL_SetRenderDrawColor(gRenderer, 255, 255, 255, 255);
SDL_RenderClear(gRenderer);
printf("tot ecranul\n");
break;
}
case SDLK_1:
{
SDL_Rect rect = {e.motion.x - 8, e.motion.y - 8, 16, 16};
SDL_RenderCopy(gRenderer, gT[3], NULL, &rect);
printf("1\n");
break;
}
}
break;
}
}
I tried some random things, and no success so far.
gT[3] is the "1" texture.
e.motion only makes sense when e is a mouse event.
Call SDL_GetMouseState to get the current mouse position.

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.

Event handling bug with SDL

I am making a snake game using SDL and C++, and I found a bug involving events.
In this game, there are two important functions for now : the play function (the "main" function of the game) and the pause function. When the P key is pressed, the play function calls and executes the pause function. In it, you have two possibilities: either continue or quit the game.
Now, here is the problem. When I try to click "Continue game", the game flashes for a split second and comes back to the pause menu. When I keep the mouse button down, I realize the game itself is frozen until an event of any kind happens. If it does, it just comes back to where it was.
After some tests, I also noticed that the bug was due to the SDL_PollEvent function. So I changed this function in the play function to SDL_WaitEvent, which put the game back when I asked him to. However, another problem is created: since, in my play function, there is a timer that uses SDL_GetTicks, the game needs a trigger event to be fluid. For example, when I constantly move the cursor in any direction, the game can run. When I stop, it freezes.
Is there a way to fix this bug?
Here is the event handler in the play function:
SDL_PollEvent(&event); // Handle events
switch(event.type)
{
case SDL_QUIT:
quit = true;
break;
case SDL_KEYDOWN:
switch(event.key.keysym.sym) // Change direction at certain key press
{
case SDLK_s:
currentDirection = SNAKE_DOWN;
break;
case SDLK_w:
currentDirection = SNAKE_UP;
break;
case SDLK_a:
currentDirection = SNAKE_LEFT;
break;
case SDLK_d:
currentDirection = SNAKE_RIGHT;
break;
case SDLK_ESCAPE: // Quit if escape key pressed
quit = true;
break;
case SDLK_p:
if (pause(screen) == false)
quit = true;
break;
break;
default: ; // Code to block the compiler's -Wall flag (does not do anything to the program itself)
}
break;
}
And here is the complete pause function:
bool pause(SDL_Surface *screen)
{
SDL_Surface *pauseMessage, *continueButton, *quitButton;
SDL_Rect posPauseMessage, posContinueButton, posQuitButton;
TTF_Font *fipps;
SDL_Color color = {255, 255, 255};
SDL_Event event;
int x = 0, y = 0;
bool quit = false, returnFalse = false;
fipps = TTF_OpenFont("fipps.ttf", 50);
pauseMessage = TTF_RenderText_Blended(fipps, "PAUSED", color);
continueButton = TTF_RenderText_Blended(fipps, "Continue Game", color);
quitButton = TTF_RenderText_Blended(fipps, "Exit to menu", color);
posPauseMessage.x = (screen->w - pauseMessage->w) / 2;
posPauseMessage.y = 200;
posContinueButton.x = (screen->w - continueButton->w) / 2;
posContinueButton.y = posPauseMessage.y + 200;
posQuitButton.x = (screen->w - quitButton->w) / 2;
posQuitButton.y = posContinueButton.y + 100;
while (!quit)
{
SDL_WaitEvent(&event);
switch(event.type)
{
case SDL_QUIT:
returnFalse = true;
quit = true;
break;
case SDL_MOUSEBUTTONUP:
x = event.button.x;
y = event.button.y;
if ((x > posContinueButton.x) && (x < posContinueButton.x + continueButton->w) && (y > posContinueButton.y) && (y < posContinueButton.y + continueButton->h))
quit = true;
else if ((x > posQuitButton.x) && (x < posQuitButton.x + quitButton->w) && (y > posQuitButton.y) && (y < posQuitButton.y + quitButton->h))
returnFalse = true;
quit = true;
break;
}
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
SDL_BlitSurface(pauseMessage, NULL, screen, &posPauseMessage);
SDL_BlitSurface(continueButton, NULL, screen, &posContinueButton);
SDL_BlitSurface(quitButton, NULL, screen, &posQuitButton);
SDL_Flip(screen);
}
TTF_CloseFont(fipps);
SDL_FreeSurface(pauseMessage);
SDL_FreeSurface(continueButton);
SDL_FreeSurface(quitButton);
if (returnFalse)
return false;
return true;
}
Thanks to #jordsti, I found a solution : I need to put the SDL_PollEvent as a condition for a while loop, which contains the switch block.

SDL_EventState toggle

I've been using SDL_EventState as to disable and enable certain events. However for some reason once I set any state to either on or off, no where else in the program can I change it. To explain further, here is my loop.
void game::startLoop()
{
while(QUIT == false)
{
getRoomUpdate();
applySurface(-15, 280, zombie_lefthand, buffer);
applySurface(455, 280, zombie_righthand, buffer);
SDL_Flip(buffer);
SDL_WaitEvent(&gameEvent);
{
switch(gameEvent.type)
{
case SDL_QUIT:
QUIT = true;
break;
case SDL_KEYUP:
switch(gameEvent.key.keysym.sym)
{
case SDLK_LEFT:
if(isTwoWay == true)
SDL_EventState(SDL_KEYUP, 1);
startLoop();
log("Left key pressed.");
SDL_EventState(SDL_KEYUP, 0);
case SDLK_RIGHT:
if(isTwoWay == true)
SDL_EventState(SDL_KEYUP, 1);
startLoop();
log("Right key pressed.");
SDL_EventState(SDL_KEYUP, 0);
case SDLK_UP:
if(isTwoWay == false)
SDL_EventState(SDL_KEYUP, 1);
startLoop();
log("Up key pressed.");
SDL_EventState(SDL_KEYUP, 0);
default:
SDL_EventState(SDL_KEYUP, 0);
}
}
}
}
}
Perhaps if you tried someone else's code.
If it worked you could try to transform their code to something like yours(functionally wise)
Good Luck!
p.s. I think you should use SDL_ENABLE and SDL_DISABLE.

SDL doesn't detect Arrow Keys

I am working through the SDL tutorials over at http://lazyfoo.net/SDL_tutorials/index.php and I'm stuck on tutorial 8 where I'm working with key presses.
I'm using the following code:
//Our Main application loop
while(!quit){
if(SDL_PollEvent(&curEvents)){
if(curEvents.type == SDL_QUIT){
quit = true;
}
//If a key was pressed
if( curEvents.type == SDL_KEYDOWN )
{
//Set the proper message surface
switch( curEvents.key.keysym.sym )
{
case SDLK_UP:
message = upMessage;
break;
case SDLK_DOWN:
message = downMessage;
break;
case SDLK_LEFT:
message = leftMessage;
break;
case SDLK_RIGHT:
message = rightMessage; break;
default:
message = TTF_RenderText_Solid(font, "Unknown Key", textColor);
break;
}
}
}
if( message != NULL )
{
//Apply the background to the screen
applySurface( 0, 0, background, screen );
//Apply the message centered on the screen
applySurface( ( SCREEN_WIDTH - message->w ) / 2, ( SCREEN_HEIGHT - message->h ) / 2, message, screen );
//Null the surface pointer
message = NULL;
}
//Update the screen
if( SDL_Flip( screen ) == -1 )
{
return 1;
}
}
Where works fine, the default case is reached, for everything BUT pressing the arrow keys. I was wondering if someone could spot what I'm doing wrong.
I discovered the error which was not in the code posted above. The error was that for the arrow keypress messages, I used RenderText before the font was opened. By the time the posted code block was reached, font had already been opened and is the reason why that message shows.