SDL x and y movement - c++

Why wont this code let me move up or left?
while( quit == false )
{
apply_surface( 0,0, back,screen );
apply_surface( playerx,playery,player, screen );
SDL_Flip( screen );
//While there's an event to handle
while( SDL_PollEvent( &event ) )
{
if(event.type == SDL_KEYDOWN)
{
switch(event.key.keysym.sym)
{
case SDLK_UP:playery=playery-10;
case SDLK_DOWN:playery=playery+10;
case SDLK_LEFT:playerx=playerx-10;
case SDLK_RIGHT:playerx=playerx+10;
}
}

You need to use a break after each case in the switch Otherwise the execution "falls through" to the next line, potentially cancelling your action (and indeed SDLK_UP and SDLK_LEFT are the ones where the cancellation happens)

Related

The correct way to test 'SDL_PollEvent' in a 'while'

As the manual says, the function SDL_PollEvent "Returns 1 if there is a pending event or 0 if there are none available." , that's why we use the test SDL_PollEvent(&e)!=0 (where e is a SDL_Event).
But, what about use this test: !SDL_PollEvent(&e)? It should work,but apparently it cause some problem.
Here an example of code:
#include <SDL2/SDL.h>
#include <stdio.h>
int main(int argc, char* args[]){
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window = SDL_CreateWindow("Hello",SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 100, 100, SDL_WINDOW_SHOWN);
SDL_Event e;
int quit=0;
while(!quit){
//Here the test
while (!SDL_PollEvent(&e)){
if (e.type==SDL_QUIT)
quit=1;
else if ( e.type == SDL_KEYDOWN )
printf( "Hello\n" );
}
}
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
What this code should do is open a new window and print "Hello" in the console every time a key is pressed. This code works fine whit the test SDL_PollEvent(&e)!=0 but it doesn't read the SDL_KEYDOWN event when I use the test !SDL_PollEvent(&e) (but it DOES enter in the while and process the SDL_QUIT event without any problem).
Why this behaviour?
while (!SDL_PollEvent(&e))
needs to be:
while (SDL_PollEvent(&e))
if it should be the same as SDL_PollEvent(&e) != 0
because !SDL_PollEvent(&e) is the same as calling while(0)
(1 != 0) is true, but (!1) is false.
You probably should use SDL_WaitEvent instead anyway.
Addendum
One may think it's more clear to do something like this, since it ensures that user input is reacted upon. However, this is currently an OS dependent and possibly crazy CPU hog and will max out your CPU for this thread (on Windows). So you may think that you can just put a 1 second wait there, but then your window will become completely unresponsive or very laggy at best...
If you can live with a little CPU overhead for doing nothing, then you can compromise with using an 20-100 [ms] delay.
...
// Set the event handler...
...
bool isRunning = true;
while (isRunning) {
// Do the main thing here...
...
while(SDL_PollEvent(&windowEvent)) {
switch (windowEvent.type) {
case SDL_QUIT: isRunning = false;
case SDL_KEYDOWN: isRunning = false;
case SDL_MOUSEBUTTONDOWN: isRunning = false;
break;
}
SDL_Delay(100); // Wrong!
}
}
// End the program
So clearly this is not the correct way either. We need to use some other mechanism. Looking at the SDL repo, we find a long but very relevant discussion for the open issue:
SDL_WaitEvent causes high cpu usage
To Fix the issue
Make sure you put the delay in the outer loop, before the SDL_PollEvent().
// main loop
...
while(SDL_PollEvent(&windowEvent)) {
switch (windowEvent.type) {
case SDL_QUIT: isRunning = false;
case SDL_KEYDOWN: isRunning = false;
case SDL_MOUSEBUTTONDOWN: isRunning = false;
break;
}
}
SDL_Delay(100); // Right!
}

SDL event loop quitting?

I am making an RTS in C++ using SDL for graphics.
Every time I run the game, it crashes without errors or anything in the compiler debug window. It doesn't crash immediately or consistently, sometimes taking 10 seconds to crash and other times taking 2 minutes to crash.
When I played around with return values (at the end of the main function) it turned out it wasn't crashing, but rather quitting as the return values were consistent with what I changed it to.
The only theory that I have is that my poll event loop is glitching and telling the program to quit when it isn't supposed to.
Here is my event loop, contained within my game loop:
if( SDL_PollEvent( &event ) )
{
if( event.type == SDL_MOUSEMOTION )
{
mx = event.motion.x;
my = event.motion.y;
}
if( event.type == SDL_MOUSEBUTTONDOWN )
{
if( hut.getselected() && hut.getplacable() )
{
hut.place( map );
}
}
if( event.type == SDL_QUIT )
{
quit = true;
}
switch( event.key.keysym.sym )
{
case SDLK_ESCAPE: quit = true; break;
}
}
Is it possible that when the mouse moves or clicks, that it is confusing it for exiting? I don't think the ram is overloading either because it only displays what it needs to tile-wise.
Is it also possible that my compiler, VisualC++, is screwing up?
How about changing the switch at end of your snippet to:
if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE) {
quit = true;
}
Because in your code you check keysym for all events, so usually event is of wrong type when you test if it is escape, and you get "garbage" value for keysym, and sometimes it matches with ESC.
Actually might be good idea to test the event.type with switch:
switch(event.type) {
case SDL_MOUSEMOTION:
//....
break;
case SDK_KEYDOWN:
switch(event.key.keysym.sym) {
case SDLK_ESCAPE:
quit = true;
break;
// cases for other keypresses
}
break;
// cases for other events
}

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.

How can I clear a SDL_Surface to be replaced with another one?

Been trying to find this online for a while now.
I have a SDL_Surface with some content (in one it's text, in another is a part of a sprite). Inside the game loop I get the data onto the screen fine. But then it loops again and it doesn't replace the old data but just writes over it. So in the case of the text, it becomes a mess.
I've tried SDL_FreeSurface and it didn't work, anyone know another way?
fpsStream.str("");
fpsStream << fps.get_ticks();
fpsString = fpsStream.str();
game.fpsSurface = TTF_RenderText_Solid(game.fpsFont, fpsString.c_str(), textColor);
game.BlitSurface(0, 0, game.fpsSurface, game.screen);
Try something like:
SDL_FillRect(screen, NULL, 0x000000);
at the beginning of your loop.
What I do usually is drawing to a secondary surface (that is, an in-memory surface that's not the screen) and then SDL_BlitSurface when it's ready to be copied to the screen. You can then clear the whole secondary buffer (with SDL_FillRect) in the next iteration and redraw everything or just a part of if you don't want to lose the whole surface and only changed a rectangle.
This way, you also get doublebuffering and avoid flickering. Also don't forget SDL_UpdateRects after blitting.
If you are drawing something with transparency (eg. stuff from SDL_ttf) then the transparent areas between the text won't be altered, meaning previous writes will remain. This isn't usually a problem because the usual behaviour is for the program to clear the frame buffer and redraw the entire scene once per frame. In the old days it was common to only redraw the 'dirty' parts of the screen but that is not so common now.
while( !quit )
{
while( SDL_PollEvent( &e ) != 0)
{
if( e.type == SDL_QUIT )
{
quit = true;
}
else if( e.type == SDL_KEYDOWN)
{
**SDL_FillRect(screenSurface, NULL, 0x000000);**
switch(e.key.keysym.sym)
{
case SDLK_w:
CurrentSurface = ImageSurfaces[ KEY_PRESS_SURFACE_UP ];
break;
case SDLK_d:
CurrentSurface = ImageSurfaces[ KEY_PRESS_SURFACE_RIGHT ];
break;
case SDLK_s:
CurrentSurface = ImageSurfaces[ KEY_PRESS_SURFACE_DOWN ];
break;
case SDLK_a:
CurrentSurface = ImageSurfaces[ KEY_PRESS_SURFACE_LEFT ];
break;
default:
CurrentSurface = ImageSurfaces[ KEY_PRESS_SURFACE_DEFAULT ];
break;
}
}
}
SDL_BlitSurface(CurrentSurface, NULL, screenSurface, NULL);
SDL_UpdateWindowSurface( window );
}

hardware buffering using SDL, question about how it works

I'm deciding to do my first game, its going to be simple but I want to use c++ and I chose SDL for my learning. So my question is about how the "buffers" are handled when writing code. I'll post my related code at the bottom.
Ok, so basically the way I understand it is that SDL takes care of which buffer is actually being drawn to the screen. When I am writing to a buffer it is always the backbuffer I am writing to, or the buffer currently not being drawn on the screen. So, when I call SDL_Flip(screen) it "blits" my screen surface onto the backbuffer, then moves the pointer to which buffer is being drawn to that buffer which used to be the backbuffer, the one I had been working on, and the old buffer that was showing now becomes the backbuffer. At this point if I call SDL_FillRect(arguments) it will be performed on the now back buffer?
I'm going to post my entire "heartbeat" of my learning game as it may help clarify my question:
//While the user hasn't quit
while( quit == false )
{
//If there's an event to handle
if( SDL_PollEvent( &event ) )
{
//If a key was pressed
if( event.type == SDL_KEYDOWN )
{
//Set the proper message surface
switch( event.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;
}
}
else if( event.type == SDL_QUIT ) //if the user clicks the little X in the upper right corner.
{
quit = true;
}
}
//If a message needs to be displayed
if( message != NULL )
{
// Clear the back buffer.
SDL_FillRect( SDL_GetVideoSurface(), NULL, 0 );
//Draw the backgroudn to the back buffer.
apply_surface( 0, 0, background, screen );
// Draw the "message" to the back buffer.
apply_surface( ( SCREEN_WIDTH - message->w ) / 2, ( SCREEN_HEIGHT - message->h ) / 2, message, screen );
//Null the surface pointer
message = NULL;
}
//Swap the current and back buffer.
if( SDL_Flip( screen ) == -1 )
{
return 1;
}
}
it highly depends on the your system (ie. X11, Linux frame buffer, Windows), and the backend SDL uses to interact with it. Also which flags you passs to SDL_SetVideoMode. There are basically software surfaces which sit in a region of memory in you program and hardware surfaces which are placed in graphical card's memory. What you describe seems to me to be a double buffer, which is enabled if you pass SDL_HWSURFACE | SDL_DOUBLEBUF to SDL. Just remember this is not supported on all platforms and configurations and you may get something different instead.