Question

I'm a beginner in c++ and games programming and am trying to create a game which accepts a series of keyboard inputs from the user and on pressing enter should display the movements of a sprite in a sequence based on the keys pressed.

I am using SDL 2 and have been able to move my sprite as soon as each key is pressed but I would like to wait for all the inputs and then show all the movements successively once the user presses the ENTER key. So far I came up with the following code shown below.

(I have used a counter variable to save the number of times any arrow key is pressed and a sprite class which stores its position and velocity on screen).

SDL_Event e;
bool quit = false;
bool startSprite = false;
Sprite sprite1;
while (!quit)
{
    while (SDL_PollEvent(&e) && startSprite== false)
    {
        if (e.type == SDL_QUIT)
        {
            quit = true;
        }
        if (e.type == SDL_KEYDOWN || e.type == SDL_KEYUP)
        {
            //true if ENTER key is pressed
            if (e.key.keysym.sym == SDLK_RETURN)
            {
                startSprite = true;

            }
            //Handle input for the sprite
            sprite1.handleEvent(e);
        }

    }

    //if the ENTER key is pressed
    if(startSprite==true)
    {
        //Clear the window
        SDL_RenderClear(renderer);

        drawTiles(xTiles, yTiles, background, renderer);

           //if the counter > 0, loop through and display each movement until the 
           //total count number is reached

        if(count>0)
        {
            for(int i=0;i<count;i++)
            {
            sprite1.move();

            //display the image
            drawImages(image, image2, image3, sprite1, renderer);

            //Update the screen
            SDL_RenderPresent(renderer);
            }
            count=0;
        }
        //startSprite==false;
    }

The code for handling the sprite event

void Sprite::handleEvent( SDL_Event& e )
{
    //If a key was pressed
if( e.type == SDL_KEYDOWN  ) //&& e.key.repeat == 0
    {
       //Adjust the velocity
       switch( e.key.keysym.sym )
       {
          case SDLK_UP: mVelY -= SPRITE_VEL; break;
          case SDLK_DOWN: mVelY += SPRITE_VEL; break;
          case SDLK_LEFT: mVelX -= SPRITE_VEL; break;
          case SDLK_RIGHT: mVelX += SPRITE_VEL; break;
      case SDLK_RETURN: startSprite=true; break;
       }
   count++; 
    }
    //If a key was released
    else if( e.type == SDL_KEYUP  ) //&& e.key.repeat == 0
    {
        //Adjust the velocity
        switch( e.key.keysym.sym )
       {
           case SDLK_UP: mVelY += SPRITE_VEL; break;
           case SDLK_DOWN: mVelY -= SPRITE_VEL; break;
           case SDLK_LEFT: mVelX += SPRITE_VEL; break;
           case SDLK_RIGHT: mVelX -= SPRITE_VEL; break;
       case SDLK_RETURN: startSprite=true; break;
       }
   }
}

The move function of the sprite class

void Sprite::move()
{
  //Move the sprite left or right
  mPosX += mVelX;

  //If the sprite went too far to the left or right
  if( ( mPosX < 0 ) || ( mPosX + SPRITE_WIDTH > SCREEN_WIDTH ) )
  {
    //Move back
    mPosX -= mVelX;
  }

  //Move the sprite up or down
  mPosY += mVelY;

  //If the sprite went too far up or down
  if( ( mPosY < 0 ) || ( mPosY + SPRITE_HEIGHT > SCREEN_HEIGHT ) )
  {
    //Move back
    mPosY -= mVelY;
  }
}

This doesn't work however and my code never leaves the while loop because of startSprite not setting to true for some reason.

If I remove the condition from the while loop statement, then, after pressing the arrow keys in order and then pressing enter nothing happens

and then if I press an arrow key to move the sprite, the sprite moves with each key press. I am completely confused and have been at this all day. I can't seem to figure out where I am going wrong.

Was it helpful?

Solution

I was going to write this in a comment, but it became too long. It might not be the answer you're looking for...

If you think of the logic in your code, it seems what will happen when you press a key that is not enter is that the handleEvent will run and the velocity will be adjusted, and when you finally press enter the move loop takes over and starts moving the sprite, but... if you pressed up once and down once, the velocity will be unchanged as the moves counteract each other, and the move will be two times nothing.

What you need to do is to defer the handling of events until you press return altogether, so that you start processing the events only after you hit enter.

If you add the events to a std::queue<SDL_Event> (using queue.push_back(e)) you can retrieve them in a loop after you hit enter and for each event call the handleEvent and move functions, possibly with a small delay if you actually want to see the moves performed stepwise.

it could look something like this:

while (!queue.empty())
{
    SDL_Event e = queue.front();
    sprite1.handleEvent(e);
    SDL_RenderClear(renderer);
    drawTiles(xTiles, yTiles, background, renderer);
    sprite1.move();
    drawImages(image, image2, image3, sprite1, renderer);

    SDL_Delay(200); // possible delay.

    SDL_RenderPresent(renderer);

    queue.pop();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top