SDL Moving Picture

Started by
7 comments, last by Somtin 15 years, 9 months ago
1. How can I have a non-stop moving of my picture? That means, that I want to hit an arrow key, an the increment of the variable X or Y does not stop. Still just now I have to hit the key all the time again. 2. The LEFT and UP Key don't work? Only RIGHT and DOWN work. How to solve this problem? Can help me anybody please? Here's the Code:

#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include <string>
using namespace std;

SDL_Surface * LoadImage(const string &filename);
bool ApplySurface(short x, short y, SDL_Surface *source, SDL_Surface *destination, SDL_Rect *frame = NULL);

SDL_Surface *screen = NULL;
const short SCREEN_X = 640;
const short SCREEN_Y = 480;
const short SCREEN_COLOUR = 32;

int main(int argc, char *args[])
{
    //Variables
    SDL_Surface *background = NULL;
    SDL_Event event;
    bool exit = false;
    short X=0;
    short Y=0;

    //Initialisation
    if(SDL_Init(SDL_INIT_EVERYTHING) == -1)
    {
        return 1;
    }

    screen = SDL_SetVideoMode(SCREEN_X, SCREEN_Y, SCREEN_COLOUR, SDL_SWSURFACE);
    if(screen == NULL)
    {
        return 1;
    }

    background = LoadImage("keen6art.jpg");
    if(background == NULL)
    {
        return 1;
    }



    while(exit == false)
    {
        while(SDL_PollEvent(&event))
        {
            if(event.type == SDL_QUIT)
            {
                exit = true;
            }

            if(event.type == SDL_KEYDOWN)
            {
                switch( event.key.keysym.sym )
                {
                    case SDLK_UP: Y=Y-4;
                    case SDLK_DOWN: Y=Y+4;
                    case SDLK_LEFT: X=X-4;
                    case SDLK_RIGHT: X=X+4;
                    default:;
                }
            }


        }

        if(SDL_Flip(screen) == -1)
        {
                return 1;
        }

        if(!ApplySurface(X,Y,background,screen)) return 1;
    }

    SDL_FreeSurface(background);
    SDL_Quit();

    return 0;
}

SDL_Surface * LoadImage(const string &filename)
{
    SDL_Surface *loadedImage = NULL;
    SDL_Surface *optimizedImage = NULL;
    loadedImage = IMG_Load(filename.c_str());
    if(loadedImage != NULL)
    {
        optimizedImage = SDL_DisplayFormat(loadedImage);
        SDL_FreeSurface(loadedImage);
    }
    return optimizedImage;
}

bool ApplySurface(short x, short y, SDL_Surface *source, SDL_Surface *destination, SDL_Rect *frame)
{
    SDL_Rect offset;
    offset.x = x;
    offset.y = y;
    if(SDL_BlitSurface(source, frame, destination, &offset) != -1)
    {
        return true;
    }
    else
    {
        return false;
    }
}
3. How can I improve my Code? If you can find style erros...or if you know a better way for me to do something, please tell me! Only on this way I cann improve myself. Stromberg
Advertisement
1. Use SDL_GetKeyState to determine if a key is currently held down each frame. The SDL_KEYDOWN event only fires once when you press the key down. If you must use events, you could e.g. set a flag on the SDL_KEYDOWN event and clear it on the corresponding SDL_KEYUP to keep track of just the arrow keys' state.

2. Your switch is broken because you don't have a "break;" between the cases. This means that when you press left, the program continues to also execute the "right" case and results in no movement.
If you want the movement to be non-stop you're going to need some code to keep updating the sprites position in the specified direction when the key is not pressed. Currently the position is only changed on a key press event. In addition to the x and y position I would have xVelocity and yVelocity
so that the increment is x += xVelocity and y += yVelocity. Every time a key is press the appropriate velocity is incremented or decremented by a fixed amount, 4 for example, and each through your loop you increment y an x by yVelocity and xVelocity respectively.

I recommend you add breaks to your cases eg:
case SDLK_UP:   Y=Y-4;  break;




hope that helps.
Patrick
Now I made it this way. But although the non stop increment doesn't work.

#include "SDL/SDL.h"#include "SDL/SDL_image.h"#include <string>using namespace std;SDL_Surface * LoadImage(const string &filename);bool ApplySurface(short x, short y, SDL_Surface *source, SDL_Surface *destination, SDL_Rect *frame = NULL);SDL_Surface *screen = NULL;const short SCREEN_X = 640;const short SCREEN_Y = 480;const short SCREEN_COLOUR = 32;int main(int argc, char *args[]){    //Variables    SDL_Surface *background = NULL;    SDL_Event event;    bool exit = false;    short X=0;    short Y=0;    Uint8 *allKeys = SDL_GetKeyState (NULL); //???    //Initialisation    if(SDL_Init(SDL_INIT_EVERYTHING) == -1)    {        return 1;    }    screen = SDL_SetVideoMode(SCREEN_X, SCREEN_Y, SCREEN_COLOUR, SDL_SWSURFACE);    if(screen == NULL)    {        return 1;    }    background = LoadImage("keen6art.jpg");    if(background == NULL)    {        return 1;    }    while(exit == false)    {        while(SDL_PollEvent(&event))        {            if(event.type == SDL_QUIT)            {                exit = true;            }            //???            if (allKeys[SDLK_UP]) Y=Y-4;            if (allKeys[SDLK_DOWN]) Y=Y+4;            if (allKeys[SDLK_LEFT]) X=X-4;            if (allKeys[SDLK_RIGHT]) X=X+4;            if(SDL_Flip(screen) == -1)            {                return 1;            }            if(!ApplySurface(X,Y,background,screen)) return 1;        }    }    SDL_FreeSurface(background);    SDL_Quit();    return 0;}SDL_Surface * LoadImage(const string &filename){    SDL_Surface *loadedImage = NULL;    SDL_Surface *optimizedImage = NULL;    loadedImage = IMG_Load(filename.c_str());    if(loadedImage != NULL)    {        optimizedImage = SDL_DisplayFormat(loadedImage);        SDL_FreeSurface(loadedImage);    }    return optimizedImage;}bool ApplySurface(short x, short y, SDL_Surface *source, SDL_Surface *destination, SDL_Rect *frame){    SDL_Rect offset;    offset.x = x;    offset.y = y;    if(SDL_BlitSurface(source, frame, destination, &offset) != -1)    {        return true;    }    else    {        return false;    }}


PS: Excuse my bad english.

Stromberg
1. Now I made it with the Function "SDL_EnableKeyRepeat". And it works good.
What do you think about? How can I still improve the Code?

2. I want to hit 2 arrow keys simultaneous. For exemple, LEFT + DOWN. But it does not work. Only LEFT works in this combination.
But how can I hit keys simultaneous?

CODE:
#include "SDL/SDL.h"#include "SDL/SDL_image.h"#include <string>using namespace std;SDL_Surface * LoadImage(const string &filename);bool ApplySurface(short x, short y, SDL_Surface *source, SDL_Surface *destination, SDL_Rect *frame = NULL);SDL_Surface *screen = NULL;const short SCREEN_X = 640;const short SCREEN_Y = 480;const short SCREEN_COLOUR = 32;int main(int argc, char *args[]){    //Variables    SDL_Surface *background = NULL;    SDL_Event event;    bool exit = false;    short X=0;    short Y=0;    Uint8 *allKeys = SDL_GetKeyState (NULL); //???    //Initialisation    if(SDL_Init(SDL_INIT_EVERYTHING) == -1)    {        return 1;    }    screen = SDL_SetVideoMode(SCREEN_X, SCREEN_Y, SCREEN_COLOUR, SDL_SWSURFACE);    if(screen == NULL)    {        return 1;    }    background = LoadImage("keen6art.jpg");    if(background == NULL)    {        return 1;    }    SDL_EnableKeyRepeat ( 1, 10); // <- !!!    while(exit == false)    {        while(SDL_PollEvent(&event))        {            if(event.type == SDL_QUIT)            {                exit = true;            }            if(event.type = SDL_KEYDOWN)            {                switch(event.key.keysym.sym)                {                    case SDLK_UP:                    Y=Y-1;                    break;                    case SDLK_DOWN:                    Y=Y+1;                    break;                    case SDLK_RIGHT:                    X=X+1;                    break;                    case SDLK_LEFT:                    X=X-1;                    break;                    default:                    break;                }            }            if(SDL_Flip(screen) == -1)            {                return 1;            }            if(!ApplySurface(X,Y,background,screen)) return 1;        }    }    SDL_FreeSurface(background);    SDL_Quit();    return 0;}SDL_Surface * LoadImage(const string &filename){    SDL_Surface *loadedImage = NULL;    SDL_Surface *optimizedImage = NULL;    loadedImage = IMG_Load(filename.c_str());    if(loadedImage != NULL)    {        optimizedImage = SDL_DisplayFormat(loadedImage);        SDL_FreeSurface(loadedImage);    }    return optimizedImage;}bool ApplySurface(short x, short y, SDL_Surface *source, SDL_Surface *destination, SDL_Rect *frame){    SDL_Rect offset;    offset.x = x;    offset.y = y;    if(SDL_BlitSurface(source, frame, destination, &offset) != -1)    {        return true;    }    else    {        return false;    }}


Thanks

Stromberg
SDL_EnableKeyRepeat is almost always the wrong thing to do, unless you're collecting text input (eg. for a text box). It will just keep generating the last event over and over, which is no good for you here.

Either check SDL_GetKeyState for all keys you're interested in instead of checking events, or change a velocity value on the object when keys are pressed and released and update their position based on that.
Mh, I've still got a problem. With SDL_GetKeyState, I can only find out if a key was pressed, not if the key is pressed! But I want to know if a key is pressed. How to find out about that?

Stromberg
Quote:Original post by Stromberg
Mh, I've still got a problem. With SDL_GetKeyState, I can only find out if a key was pressed, not if the key is pressed! But I want to know if a key is pressed. How to find out about that?

Stromberg


Would you mind elaborating on that? SDL_GetKeyState gets the current key state.
replace your main function with this..

int main(int argc, char *args[])

{

//Variables

SDL_Surface *background = NULL;

SDL_Event event;

bool exit = false;

short Xvel=0;

short Yvel=0;

short X=0;

short Y=0;



//Initialisation

if(SDL_Init(SDL_INIT_EVERYTHING) == -1)

{

return 1;

}



screen = SDL_SetVideoMode(SCREEN_X, SCREEN_Y, SCREEN_COLOUR, SDL_SWSURFACE);

if(screen == NULL)

{

return 1;

}



background = LoadImage("keen6art.jpg");

if(background == NULL)

{

return 1;

}







while(exit == false)

{

while(SDL_PollEvent(&event))

{

if(event.type == SDL_QUIT)

{

exit = true;

}



if(event.type == SDL_KEYDOWN)

{

switch( event.key.keysym.sym )

{

case SDLK_UP: Yvel=-4;

case SDLK_DOWN: Yvel=4;

case SDLK_LEFT: Xvel=-4;

case SDLK_RIGHT: Xvel=4;

}

}

if(event.type == SDL_KEYUP)

{

switch( event.key.keysym.sym )

{

case SDLK_UP: Yvel=0;

case SDLK_DOWN: Yvel=0;

case SDLK_LEFT: Xvel=0;

case SDLK_RIGHT: Xvel=0;

}

}




}



if(SDL_Flip(screen) == -1)

{

return 1;

}

X += Xvel;
Y += Yvel;

if(!ApplySurface(X,Y,background,screen)) return 1;

}



SDL_FreeSurface(background);

SDL_Quit();



return 0;

}

This checks for a key down event, and sets the velocity to 4. When it sees a key up event, it puts it back. This should work for pressing two buttons together, ie Up and Right. If you wanted the values to add up, so your image got faster and faster, change the four case SDLK_ lines in the SDL_KEYDOWN if, so that it says Xvel += 4, or Xvel -= 4 and the same with the Yvel.

Thats what I have used in the past, but I just added those modifications in from memory.. they might be slightly wrong.

This topic is closed to new replies.

Advertisement