Hi!

The keypresses in my new project does not seem to be registered. I've never had this issue before and I don't think it is SDL:s fault this time.

Here is the code in main:

#include <cstdlib>
#include <iostream>

#include <SDL.h>

#include "playertank.h"

int main ( int argc, char** argv )
{
    SDL_Init(SDL_INIT_VIDEO);

    SDL_Surface* screen = SDL_SetVideoMode(720, 480, 24, SDL_HWSURFACE|SDL_DOUBLEBUF);
    SDL_Surface* background = SDL_LoadBMP("Grass.bmp");
    SDL_Surface* tank_body = SDL_LoadBMP("TankBody.bmp");

    PlayerTank player1(200,200,32,32,10);

    SDL_SetColorKey( tank_body, SDL_SRCCOLORKEY, SDL_MapRGB(screen->format, 0, 255, 255) );

    bool quit = false;
    while(!quit)
    {
    //Controls
        player1.move(SDL_GetKeyState(NULL));

    //logics


    //draw
        SDL_BlitSurface(background, NULL,screen,NULL);
        SDL_BlitSurface(tank_body,NULL,screen,player1.getPos());
        SDL_Rect* copy = player1.getPos();
        std::cout<<copy->y<<std::endl;
        SDL_Delay(100);
        SDL_Flip(screen);
    }

    atexit(SDL_Quit);
    return 0;
}

And here is the class:

#include "playertank.h"

PlayerTank::PlayerTank(int x, int y, int w, int h, int hp)
{
    //ctor
    pos_x = x;
    pos_y = y;
    width = w;
    height = h;

    HP = hp;
    speed = 0;
}

#include <iostream>
#define MAX_SPEED 5
void PlayerTank::move(Uint8* keystate)
{
    if(keystate[SDLK_SPACE])
    {
        if(speed <= MAX_SPEED)
            speed+=0.2;
    }
    if(keystate[SDLK_UP])
        {
            pos_y-=(int)speed;
        }
    if(keystate[SDLK_DOWN])
        {
            pos_y+=(int)speed;
        }
    if(keystate[SDLK_LEFT])
        {
            pos_x-=(int)speed;
        }
    if(keystate[SDLK_RIGHT])
        {
            pos_x+=5;
        }
    std::cout<<speed<<std::endl;
}

SDL_Rect* PlayerTank::getPos()
{

    position_copy.x = pos_x;
    position_copy.y = pos_y;
    position_copy.w = height;
    position_copy.h = width;

    return &position_copy;
}

As you can see it isn't done yet but comment on the existing parts are welcomed.

Recommended Answers

All 4 Replies

When I used SDL for graphics I don't ever remember using SDL_GetKeyState(); however, it could have been just a preference that the writer turtorials I followed had.

My suggestion (it might not be the best option) is to create your own bool array to manage the key states. You can do this by calling SDL_PollEvent() and when SDL_KEYDOWN/UP is called set the key states to true/false respectivly. The major issue that I see with this is that num lock, caps lock and scroll lock all are toggled rather than having momentary states like all the other keys. So you can treat this as a special case or just ignore it if you do not plan on using those keys for anything.

The other things that I added was a fps timer since using SDL_Delay() actually freezes the program up and I changed the starting speed for the player because you cannot move with a starting value of 0.

I didn't change the whole increasing speed method but I think having to press the space bar 5 times before you notice any change is a bit odd.

"main.cpp"

#include <cstdlib>
#include <ctime> //for the timer

using namespace std;
#include <SDL.h>

#include "playertank.h"

int main ( int argc, char** argv )
{
    SDL_Init(SDL_INIT_VIDEO);

    unsigned int curTime = clock(); //used for fps timer rather than using delay

    bool keys[SDLK_LAST]; //array of keystates

    //you might want to set the initial states to that of what SDL_GetKeyState finds
    //since for some reason it could find numlock and capslock but not anything else
    //and this method would set numlock and capslock to false
    for( int i = 0; i < SDLK_LAST; i++ )
        keys[i] = false; //set key values to false

    SDL_Surface* screen = SDL_SetVideoMode(720, 480, 24, SDL_HWSURFACE|SDL_DOUBLEBUF);
    SDL_Surface* background = SDL_LoadBMP("Grass.bmp");
    SDL_Surface* tank_body = SDL_LoadBMP("TankBody.bmp");

    PlayerTank player1(200,200,32,32,10);

    SDL_Event event; //used for event polling
    SDL_SetColorKey( tank_body, SDL_SRCCOLORKEY, SDL_MapRGB(screen->format, 0, 255, 255) );

    bool quit = false;
    while(!quit)
    {
        if( clock() - curTime >= 17 ) //fps checker (17ms ~= 60 fps)
        {
            while(SDL_PollEvent(&event)) //polls events
            {
                switch( event.type )
                {
                    //this will probably not work for caps lock and
                    //numlock so you might have to put in a special case
                    //or just ignore it if you know you will not use them
                    case SDL_KEYDOWN:
                        keys[event.key.keysym.sym] = true;
                        break;
                    case SDL_KEYUP:
                        keys[event.key.keysym.sym] = false;
                        break;
                    case SDL_QUIT:
                    {
                        atexit(SDL_Quit);
                        return 0;
                    }
                    default:
                        break;
                }
            }

            //pass in the key array
            player1.move(keys);

        //logics


        //draw
            SDL_BlitSurface(background, NULL,screen,NULL);
            SDL_BlitSurface(tank_body,NULL,screen,player1.getPos());
            SDL_Flip(screen);

            curTime = clock(); //"reset" the fps timer
        }
    }

    atexit(SDL_Quit);
    return 0;
}

"playertank.h" //my version since you didn't post it before

#ifndef PLAYERTANK_H
#define PLAYERTANK_H

#include <SDL.h>


class PlayerTank
{
    SDL_Rect position_copy;


    int pos_x;
    int pos_y;
    int width;
    int height;

    int HP;
    float speed;


    public:


    PlayerTank(int x, int y, int w, int h, int hp);

    void move(bool keys[]);
    SDL_Rect* getPos();
};


#endif

"playertank.cpp"

#include "playertank.h"
#include <iostream>
#define MAX_SPEED 5

using namespace std;

#include <SDL.h>

PlayerTank::PlayerTank(int x, int y, int w, int h, int hp)
{
    //actor
    pos_x = x;
    pos_y = y;
    width = w;
    height = h;

    HP = hp;
    speed = 5;
}


void PlayerTank::move(bool keys[])
{
    if( keys[SDLK_SPACE] )
        speed += 0.2;

    if( keys[SDLK_UP] )
        pos_y -= (int)speed;

    if( keys[SDLK_DOWN] )
        pos_y += (int)speed;

    if( keys[SDLK_LEFT] )
        pos_x -= (int)speed;

    if( keys[SDLK_RIGHT] )
        pos_x += (int)speed;
}

SDL_Rect* PlayerTank::getPos()
{

    position_copy.x = pos_x;
    position_copy.y = pos_y;
    position_copy.w = height;
    position_copy.h = width;

    return &position_copy;
}

When I added "SDL_PollEvent(&event);" it started working again. I don't see why this is necessary but it seems to be.

What Keystate does is that it gives you map of which keys that are pressed. I don't have to press the key five times to start moving, I need to hold it down for five loops. This will work as a simple acceleration. I need to adjust the timing of course but I kind of like it concept.

Thanks for the FPS-solution. I use the SDL_Delay(100) for in the very beginning only but my final versions usually have a superfluously complicated timer. I will certainly use clock() instead. However, I've been told that using the Delay() gives the computer time to focus on other things meanwhile. Isn't that better than running the test "clock() - curTime >= 17" over and over again?

When making a game I normally make a win32 window application and use SetTimer() to create a timer and then put the code that I want to be executed inside the windows message loop. I'm not 100% sure if this is any different in the end.

I have not tested this out, since I use the windows message loop, but you can try to call SetTimer() with the last parameter pointing to a function that you want to be called when the timer expires.

I would have to agree with you and say that it probably is a bad thing to run an infinite loop that checks clock() against a value to see if it is time to execute your code within. A solution to this would be to put a short delay at the end of the while() loop (I think the minimum value you can pass is 10ms) which would allow the CPU to do other tasks.

Hello,
No events were being processed because there were none in the Keystate array. According to the SDL documentation on SDL_GetKeystate you need to call SDL_PumpEvents to get a snap shot of which keys are being pressed. This function is implicitly called during SDL_PollEvent, which is why it started working when you made this call.
I hope this helps,
Beau

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.