0

I'm making a simple version of Tetris using Allegro 4 and C++. I've got most of the code in place and everything is working except user input. The keypresses are only being detected by the game on a few, random occasions. I fear it's a timing problem but I can't seem to catch it. Here are the relevant bits of code...

//Tetris.h


//Tetris class definition...

volatile long tet_counter = 0;

void increment_tet_counter()
{
  tet_counter++;
}
END_OF_FUNCTION(increment_tet_counter);

//this function gets called by the menu class when the user selects the Tetris option
//contains main loop, calls all other functions etc.
void Tetris::show(BITMAP* buffer, int& scr)
{
  LOCK_VARIABLE(tet_counter);
LOCK_FUNCTION(increment_tet_counter);
install_int_ex(increment_tet_counter, BPS_TO_TIMER(120));

while(tet_counter > 0)
{
   if(tet_scr == 1)  //welcome screen logic
   {
     if(key[KEY_E])
     {
       game_init();  //initialize game variables, etc.
       tet_scr = 2;  // go to main game screen
     }
     else if(key[KEY_I])   
     {
       tet_scr = 3;  //go to instructions screen
     }
     else if(key[KEY_Q])  //quit tetris
     {
       scr = 5;  //reference to a variable in the main.cpp, basically reverting the 
                 //main screen to the menu screen upon return
       return;
       }
   }  
   else if(tet_scr == 2)   //main game screen
   {
     if(cannot_move())   //managing auto-block movement, making the last line of blocks 
      {                  //permanent, etc... all of this works fine
       put_block();
       update_score(remove_filled_line());
       get_next_block();
      }
     move_block();  //handles auto-block movement and user input

   if(is_game_over())
    {textprintf_ex(screen, font, 500, 300, WHITE, -1, "GAME OVER!");
     rest(2000);
     tet_scr = 5;
     }

    if(key[KEY_P])  //pause game
      tet_scr = 4;

    if(key[KEY_Q])   //quit game
      tet_scr = 5;
   }

   //else ifs for other screens of the game... all work fine

  tet_counter--;                
}

//drawing functions ... work fine

}

//handles block movement... CPU-generated movement works, user input not detected mot of the time 
void Tetris::move_block()
{ 
 timer = (timer+1) % time_factor; 
 if(timer == time_factor-1)  //move block every couple of seconds
    block_y += 20;
 int k;
 if(keypressed())   //this is where the problem is (i think)
 {                  //the game only picks up the keypresses some of the times
 k = readkey();     //and sometimes when I keep the keypressed for a long time it work
  if(k >> 8 == KEY_DOWN)    //but it's very buggy and erratic and no way to predict
     block_y+=20;           //when it'll work and when it won't
  else if(k >> 8 == KEY_LEFT)
    block_x-=20;
  else if(k >> 8 == KEY_RIGHT)
    block_x+=20;
  else if(k >> 8 == KEY_UP)
    rotate_block();
 } 

 if(block_x < BOARD_X)
    block_x = BOARD_X;
 if(block_x > x_lim)
    block_x = x_lim;

 if(block_y < BOARD_Y)
    block_y = BOARD_Y;
 if(block_y > y_lim)
    block_y = y_lim;

}

//various other functions handling game logic/drawing etc are all working fine

I implemented Tetris exactly the same manner previously but without any overarching menu-class. Just run .exe and you are faced with the Tetris game. That time there were no such problems. So there is obviously something in conjunction with code outside the Tetris.h file that is mucking with the game. The only other place where I use 'keypressed()' is in the main like so...

while (counter > 0)
   {
         if(keypressed())
         {
           switch(readkey() >> 8)
           {
             case KEY_DOWN:
                  option++;
                  break;
             case KEY_UP:
                  option--;
                  break;
           }
         }

         if (option < 0)
             option = 5;
         else if (option > 5)
             option = 0;

         screen_handler(option, done);  //updates a variable using which the appropriate game is called in show_screen(), pong, breakout, snake are the other games

         counter--;
   }

   show_screen();  //this is where Tetris::show() is called
   blit(main_buffer, screen, 0, 0, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
   clear_bitmap(main_buffer);

Any and all help to fix this mess would be greatly appreciated. Thanks.

  • I'm willing to bet that its a timing issue where you need to have the key pressed down the instant that it is in the function and not past that keyPressed() check. Personally for my game I have threaded what I call an "InputProcessor" class which will Queue up Command objects based on what has been pressed. So input is not missed. See if its possible for allegro to tell you if a key has been pressed since the last time you checked(even if it is not physically down the moment you check). Also I recommend getting rid of one line if statements. Just a nasty bug waiting to happen. – Dean Knight Jun 27 '13 at 13:22
  • removing the if(keypressed()) in the main() function removes the problem in the tetris, but that of course messes up the menu selection process. any thoughts? – theSuperiorVenacava Jun 28 '13 at 13:31
  • If that keyPressed() function in the main() is being called every frame by accident, perhaps it is making the second keyPressed() call malfunction in a sense. If a call to keyPressed looks for the last key pressed since the last call then the first call could be "receiving" that key and then the second call where you actually want to receive the key is getting nada. Sometimes though you are lucky and press that key between keyPressed() call number 1 and call number 2. If this is a tight loop this could be a short window which explains the behaviors you are getting with it "working" sometimes. – Dean Knight Jun 28 '13 at 14:10
  • thanks a lot. that was indeed the problem. i added an additional condition to the if keypressed() condition in the main which now bypasses the block when tetris is running. – theSuperiorVenacava Jun 28 '13 at 20:38
  • Glad it was helpful. Will put it in answer for for future peoples reference. – Dean Knight Jun 29 '13 at 16:54

1 Answers1

0

My comment ended up solving the issue for the OP. Putting in answer form for future reference:

If that keyPressed() function in the main() is being called every frame by accident, perhaps it is making the second keyPressed() call malfunction in a sense. If a call to keyPressed looks for the last key pressed since the last call then the first call could be "receiving" that key and then the second call where you actually want to receive the key is getting nada. Sometimes though you are lucky and press that key between keyPressed() call number 1 and call number 2. If this is a tight loop this could be a short window which explains the behaviors you are getting with it "working" sometimes.

Matthew
  • 47,584
  • 11
  • 86
  • 98
Dean Knight
  • 660
  • 6
  • 17