Im having a problem with the collision in my tetris game. When the blocks collide, the block wont stop moving until it exits the entire screen. That leads to another problem: The blocks keep falling well below the screen and than collide. What could be causing this? I have a video to demonstrate this glitch:
Also here is some source code:
This is my main loop where the controls are:
int main()
{
//Initialize Allegro and all subsystems
initAllegro();
initColors();
initBitMaps();
//Screen height
int mScreenHeight = HEIGHT-78;
//Pieces
Pieces mPieces;
//Board
Board mBoard(&mPieces, mScreenHeight);
//Game
Game mGame(&mBoard, &mPieces, mScreenHeight);
//Set the state
state = -1;
ChangeState(state, title);
//Hide the windows OS mouse cursor
//al_hide_mouse_cursor(display);
//Start the main timer
al_start_timer(timer);
//Game Loop
while(!done)
{
//start the event queue
al_wait_for_event(event_queue, &events);
//Poll the keyboard
al_get_keyboard_state(&keyState);
//Check for specific key presses
if(events.type == ALLEGRO_EVENT_KEY_DOWN)
{
//Quit the game
if(events.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
done = true;
//Move the piece right
if(events.keyboard.keycode == ALLEGRO_KEY_RIGHT)
{
if(mBoard.IsPossibleMovement(mGame.mPosX+1, mGame.mPosY,
mGame.mPiece, mGame.mRotation) == true)
{
mGame.mPosX++;
}
}
//Move the piece left
if(events.keyboard.keycode == ALLEGRO_KEY_LEFT)
{
if(mBoard.IsPossibleMovement(mGame.mPosX-1, mGame.mPosY,
mGame.mPiece, mGame.mRotation) == true)
{
mGame.mPosX--;
}
}
//Move the piece down
if(events.keyboard.keycode == ALLEGRO_KEY_DOWN)
{
if(mBoard.IsPossibleMovement(mGame.mPosX, mGame.mPosY+1,
mGame.mPiece, mGame.mRotation) == true)
{
mGame.mPosY++;
}
}
//Make the piece fall down
if(events.keyboard.keycode == ALLEGRO_KEY_X)
{
while(mBoard.IsPossibleMovement(mGame.mPosX, mGame.mPosY,
mGame.mPiece, mGame.mRotation))
{
mGame.mPosY++;
}
//Store the piece in the board
mBoard.StorePiece(mGame.mPosX, mGame.mPosY-1, mGame.mPiece, mGame.mRotation);
//Check if a row of blocks has formed in the board, if so delete
mBoard.DeletePossibleLines();
//IF the top row is filled, than gameover
if(mBoard.IsGameOver())
{
ChangeState(state, ending);
}
TrackStatistics(mGame.mPiece);
//IF not, than continue the game by creating a new piece
mGame.CreateNewPiece();
}
//Rotate the piece
if(events.keyboard.keycode == ALLEGRO_KEY_Z)
{
if(mBoard.IsPossibleMovement(mGame.mPosX, mGame.mPosY, mGame.mPiece,
(mGame.mRotation+1)%4))
{
mGame.mRotation = (mGame.mRotation+1)%4;
al_play_sample_instance(rotationInstance);
}
}
//Switch from the title screen to the playing screen
if(events.keyboard.keycode == ALLEGRO_KEY_ENTER)
{
if(state == title)
ChangeState(state, playing);
}
//Switch from the playing screen to the ending
if(events.keyboard.keycode == ALLEGRO_KEY_S)
{
if(state == playing)
ChangeState(state, ending);
}
}
//Check if user closes the window
if(events.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
{
done = true;
}
///////////////////////////////////////////////////////////////
/// ///
/// Updating starts here ///
/// ///
///////////////////////////////////////////////////////////////
if(events.type == ALLEGRO_EVENT_TIMER)
{
if(state == title)
{
}
else if(state == playing)
{
if(events.timer.source == dropTimer)
{
if(mBoard.IsPossibleMovement(mGame.mPosX, mGame.mPosY+1,
mGame.mPiece, mGame.mRotation))
mGame.mPosY++;
else
{
mBoard.StorePiece(mGame.mPosX, mGame.mPosY, mGame.mPiece, mGame.mRotation);
mBoard.DeletePossibleLines();
if(mBoard.IsGameOver())
{
ChangeState(state, ending);
}
mGame.CreateNewPiece();
}
}
}
else if(state == ending)
{
}
//draw = true;
}
///////////////////////////////////////////////////////////////
/// ///
/// Rendering starts here ///
/// ///
///////////////////////////////////////////////////////////////
if(!done)
{
if(state == title)
{
al_draw_bitmap(titleScreen, 0, 0, NULL);
}
else if(state == playing)
{
al_draw_bitmap(guiScreen, 0, 0, NULL);
DrawStatistics();
//Draw the statistics screen pieces
mGame.DrawPiece(-15, -9, 0, 0);
mGame.DrawPiece(-15, -6, 1, 0);
mGame.DrawPiece(-15, -4, 2, 1);
mGame.DrawPiece(-15, -1, 3, 3);
mGame.DrawPiece(-15, 2, 4, 1);
mGame.DrawPiece(-15, 5, 5, 1);
mGame.DrawPiece(-15, 8, 6, 1);
mGame.DrawScene();
}
else if(state == ending)
{
al_draw_bitmap(endingScreen, 0, 0, NULL);
}
al_flip_display();
al_clear_to_color(al_map_rgb(0,0,0));
//draw = false;
}
}
return 0;
}
And this is my collision code and pixel location code:
/Check if the piece can be stored at this position without any collision
//Returns true if the movement is possible, false if its not possible
bool Board::IsPossibleMovement (int pX, int pY, int pPiece, int pRotation)
{
// Checks collision with pieces already stored in the board or the board limits
// This is just to check the 5x5 blocks of a piece with the appropiate area in the board
for (int i1 = pX, i2 = 0; i1 < pX + PIECE_BLOCKS; i1++, i2++)
{
for (int j1 = pY, j2 = 0; j1 < pY + PIECE_BLOCKS; j1++, j2++)
{
// Check if the piece is outside the limits of the board
if (i1 < 0 || i1 > BOARD_WIDTH - 1 ||
j1 > BOARD_HEIGHT - 1)
{
//If an actual block if the piece is outside the board,
//than movement is not possible
if (mPieces->GetBlockType (pPiece, pRotation, j2, i2) != 0)
return false;
}
// Check if the piece have collisioned with a block already stored in the map
if (j1 >= 0)
{
if ((mPieces->GetBlockType (pPiece, pRotation, j2, i2) != 0) &&
(!IsFreeBlock (i1, j1)) )
return false;
}
}
}
// No collision
return true;
}
//Store a piece in the board by filling the block
void Board::StorePiece (int pX, int pY, int pPiece, int pRotation)
{
// Store each block of the piece into the board
for (int i1 = pX, i2 = 0; i1 < pX + PIECE_BLOCKS; i1++, i2++)
{
for (int j1 = pY, j2 = 0; j1 < pY + PIECE_BLOCKS; j1++, j2++)
{
// Store only the blocks of the piece that are not empty
if (mPieces->GetBlockType (pPiece, pRotation, j2, i2) != 0)
{
mBoard[i1][j1] = POS_FILLED;
al_play_sample_instance(collideInstance);
}
}
}
}
//Returns the horizontal position (in pixels) of the block given like parameter
int Board::GetXPosInPixels(int pPos)
{
return( (BOARD_POSITION - (BLOCK_SIZE * (BOARD_WIDTH / 2))) + (pPos * BLOCK_SIZE));
}
//Returns the vertical position (in pixels) of the block given like parameter
int Board::GetYPosInPixels(int pPos)
{
return( (mScreenHeight - (BLOCK_SIZE *(BOARD_HEIGHT / 2))) + (pPos * BLOCK_SIZE));
}