   The infamous Tetris
  I am trying to make a Tetris based game. I am having trouble controlling the blocks and getting them to move down through the array. Here is what I have, can anyone help?#include <allegro.h>// Used for Timervolatile long speed_counter = 0;// Initialize allegro functions first.void init ();// Timer functionvoid increment_speed_counter();// Setting up the background and start of game.void gameSetup();// Moving the Blocksvoid moveBlock();void draw();// Global constantsconst int WIDTH = 10;const int HEIGHT = 14;// Load in BITMAPs.BITMAP *buffer;BITMAP *background;BITMAP *gBlock;// Game board 0 = empty, 1 = block  r is height c is width int gameBoard[HEIGHT][WIDTH] = {{1,1,1,1,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0}};int main(){init();gameSetup();  //Game loopwhile(!key[KEY_ESC]){while(speed_counter > 0){moveBlock();draw();blit(buffer, screen, 0, 0, 0, 0, 1024, 768);speed_counter--;}}destroy_bitmap(buffer);destroy_bitmap(gBlock);return 0;}END_OF_MAIN();void init (){allegro_init();    install_keyboard();install_timer(); // Initialize timerinstall_int_ex(increment_speed_counter, BPS_TO_TIMER(1)); //Set the BPS    set_color_depth(16);    set_gfx_mode(GFX_AUTODETECT_WINDOWED, 1024,768, 0, 0);}void increment_speed_counter(){speed_counter++;}END_OF_FUNCTION(increment_speed_counter);void gameSetup(){background = load_bitmap("background.bmp", NULL);buffer = create_bitmap(1024, 768);gBlock = load_bitmap("gBlock.bmp", NULL);    blit(background, buffer, 0, 0, 0, 0, 1024, 768);for(int r = 0; r <= 13; r++){for(int c = 0; c <= 9; c++){int glob_x = (50*c)+175;int glob_y = (50*r);if(gameBoard[r][c] == 1) blit(gBlock, buffer, 0, 0, glob_x, glob_y, 50, 50);}}}void moveBlock(){for(int r = 0; r <= HEIGHT; r++){for(int c = 0; c <= WIDTH; c++){if(c > 0 && gameBoard[r][c] == 1){gameBoard[r][c] = 1;gameBoard[r-1][c] = 0;}}}}void draw(){for(int r = 0; r <= HEIGHT; r++){for(int c = 0; c <= WIDTH; c++){if(gameBoard[r][c] == 1) blit(gBlock, buffer, 0, 0, (50*c)+175, r*50, 50, 50);}}}
  I think that your problem is that your blocks are never moving down your matrix.  This is due to the following code in your moveBlock() method:if(c > 0 && gameBoard[r][c] == 1){gameBoard[r][c] = 1;gameBoard[r-1][c] = 0;}This code sees if there is a block at a specific location on the board, and if it is there, it leaves it there and then deletes the cell above it, which is not the idea you're going for.  One way to look at it, is that at any point in the game, only 4 blocks are moving (the current tetromino)  while all of the others are stationary.  So, you could save the locations of the blocks of the current tetromino in an array of some sort, and then erase the positions of the tetromino, update the position and then re-impose the new position on the board://Holds the positions of the current tetromino.int[4] positions; //Some (x,y) representation void moveBlocks(){    for every (x,y) in positions //Iterating through the array of positions   gameBoard[x][y] = 0; //Completely erase the old block   y++; //Move the block down   //Collision testing goes here for hitting the bottom or other blocks   //...   gameBoard[x][y] = 1;  //Draw block at new location}This would always move the block downwards towards the bottom, without doing any collision detection of any kind.  This would somewhat complicate things, but the basic logic here is good... I think.Hope this helps!   ;  This is what I was originally doing and it was working kind of, but I was unable to slow it down. It would happen so fast that when I loaded the game the blocks would just be at the bottom of the screen.if(r > 0 && gameBoard[r-1][c] == 1){gameBoard[r][c] = 1;gameBoard[r-1][c] = 0;};  This is because what's happening is that when you call your move blocks method, the block is getting placed at the bottom of the screen.Consider a 5x3 matrix:011110000000000When you call the method it will start at r=0, but nothing will happen because it will fail the r>0 part of your if statement.r=1, every place that there is a block above, that block will be removed, and the placed on the line below.  Your matrix now looks like this:000000111100000r=2, the same move will occur, and your matrix will look like this:000000000001111So as you can see, in one call of your method, moveBlocks(), a block will always move to the bottom of the screen.  You will also have other problems:Consider:011100010000000at r=1, the code will generate:000000111000000So we have lost a part of the tetromino.Also, with this current method, there will be no way to lock blocks at the bottom of the screen, the blocks will always move downwards, and won't stay in place like they should in a classic game of tetris.So your current method of moving the blocks simply will not work.;  Can you offer any suggestions?I've made some progress, here is my current move block function at the end.I've definitely gotten the blocks to move down with the timer. I found out that my problem was the for loop making it happen instantly. But I did run into the problem you are describing and am currently trying to think of another way to do it.#include <allegro.h>// Used for Timervolatile long speed_counter = 0;// Initialize allegro functions first.void init ();// Timer functionvoid increment_speed_counter();// Setting up the background and start of game.void gameSetup();// Moving the Blocksvoid moveBlock();// Global constantsconst int WIDTH = 9;const int HEIGHT = 13;// Other needed global variables.int r = 0; //needed for moving row down// Load in BITMAPs.BITMAP *buffer;BITMAP *background;BITMAP *gBlock;// Game board 0 = empty, 1 = block  r is height c is width int gameBoard[HEIGHT+1][WIDTH+1] = {{1,1,0,0,0,0,0,0,0,0},    {0,1,0,0,0,0,0,0,0,0},    {0,1,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {1,0,0,0,0,0,0,0,0,0},    {1,0,0,0,0,0,0,0,0,0},    {1,1,0,0,0,0,0,0,0,0}};int main(){init();gameSetup();  //Game loopwhile(!key[KEY_ESC]){while(speed_counter > 0){  moveBlock();  blit(buffer, screen, 0, 0, 0, 0, 1024, 768);speed_counter--;}}destroy_bitmap(buffer);destroy_bitmap(gBlock);return 0;}END_OF_MAIN();void init (){allegro_init();    install_keyboard();install_timer(); // Initialize timerinstall_int_ex(increment_speed_counter, BPS_TO_TIMER(1)); //Set the BPS    set_color_depth(16);    set_gfx_mode(GFX_AUTODETECT_WINDOWED, 1024,768, 0, 0);}void increment_speed_counter(){speed_counter++;}END_OF_FUNCTION(increment_speed_counter);void gameSetup(){background = load_bitmap("background.bmp", NULL);buffer = create_bitmap(1024, 768);gBlock = load_bitmap("gBlock.bmp", NULL);    blit(background, buffer, 0, 0, 0, 0, 1024, 768);for(int r = 0; r <= 13; r++){for(int c = 0; c <= 9; c++){int glob_x = (50*c)+175;int glob_y = (50*r);if(gameBoard[r][c] == 1)blit(gBlock, buffer, 0, 0, glob_x, glob_y, 50, 50);}}}//int r=0, c2 = 0;void moveBlock(){    blit(background, buffer, 0, 0, 0, 0, 1024, 768);    r++;    for(int c = 0; c <= WIDTH; c++)    {   if(r > 0 && r <= HEIGHT && gameBoard[r][c] != 1 && gameBoard[r-1][c] == 1)   {  gameBoard[r][c] = 1;  gameBoard[r-1][c] = 0;   }    }    //if(gameBoard[r+1][0] == 1)r--;    for(int r = 0; r <= HEIGHT; r++){for(int c = 0; c <= WIDTH; c++){    if(gameBoard[r][c] == 1) blit(gBlock, buffer, 0, 0, (50*c)+175, r*50, 50, 50);}}};  First off, I would move all of the drawing functions back into the draw() method.  It is better design to have all of your drawing functions separate from your actual game code.  The one that you had in your original post seems to work fine.  That way, the moveBlock() function only concerns itself with moving blocks and not with drawing any to the screen.That being said, I think that the idea of having an array of positions of the block that is currently moving is a good one.  Here are its advantages:1)You can move only the block that is currently active (not all of the blocks)2)If done properly makes collision detection much easierSo you could have an array of ints that contains the positions of each part of the block, and then in your moveBlock method you can just:1)delete the old block(zeroing out the matrix at the positions of the currentBlock)2)increment the y position of each part of the block.3)Check if all of the new block positions are valid(not more then the height of the array, or in a spot that's already taken, in which case you would move the block back up and lock it)4)redraw the block in its new location (placing 1s in the gameBoard at the positions of the current block).   ;  Alright, I am working on that. Currently, my idea is too make 3 arrays. One array is block[4][4] which holds the position of the blocks. I then have a temporary array which is the same size as the gameboard that stores the new position of the blocks and then copies that information into the gameboard which is then printed to the screen. Once the information from the tempboard is copied to gameboard, tempboard is erased. I am working preventing the blocks that are already on the screen in gameboard from disappearing when I recopy tempboard to gameboard. I'm not 100% sure this is the right path, but I am experimenting with the ideas.#include <allegro.h>// Used for Timervolatile long speed_counter = 0;// Initialize allegro functions first.void init ();// Timer functionvoid increment_speed_counter();// Setting up the background and start of game.void gameSetup();// Moving the Blocksvoid moveBlock();// Used to draw imagesvoid draw();// Global constantsconst int WIDTH = 9;const int HEIGHT = 13;// Other needed global variables.//int r = 0; //needed for moving row down// Load in BITMAPs.BITMAP *buffer;BITMAP *background;BITMAP *gBlock;// Game board 0 = empty, 1 = block: this is what is printed to the screen r is height c is width in loopsint gameBoard[HEIGHT+1][WIDTH+1] = {{0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0}};// This is a temporary board where the position of the blocks are stored before they go into the Game board.int tempBoard[HEIGHT+1][WIDTH+1] = {{0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {0,0,0,0,0,0,0,0,0,0},    {1,0,0,0,0,0,0,0,0,0},    {1,0,0,0,0,0,0,0,0,0},    {1,1,0,0,0,0,0,0,0,0}};// This is the current position of the blocksint block[4][4] = {{0,1,0,0},    {0,1,1,0},    {0,1,0,0},    {0,0,0,0}};int main(){init();gameSetup();  //Game loopwhile(!key[KEY_ESC]){while(speed_counter > 0){draw();  moveBlock();speed_counter--;}}destroy_bitmap(buffer);    destroy_bitmap(background);destroy_bitmap(gBlock);return 0;}END_OF_MAIN();void init (){allegro_init();    install_keyboard();install_timer(); // Initialize timerinstall_int_ex(increment_speed_counter, BPS_TO_TIMER(1)); //Set the BPS    set_color_depth(16);    set_gfx_mode(GFX_AUTODETECT_WINDOWED, 1024,768, 0, 0);}void increment_speed_counter(){speed_counter++;}END_OF_FUNCTION(increment_speed_counter);void gameSetup(){background = load_bitmap("background.bmp", NULL);buffer = create_bitmap(1024, 768);gBlock = load_bitmap("gBlock.bmp", NULL);    blit(background, buffer, 0, 0, 0, 0, 1024, 768);for(int r = 0; r <= 13; r++){for(int c = 0; c <= 9; c++){if(gameBoard[r][c] == 1)blit(gBlock, buffer, 0, 0, (50*c)+175, (50*r), 50, 50);}}}int j = 0, k = 3;void moveBlock(){    int x = 0, y = 0;    for(int r = 0; r <= 3; r++){for(int c = 0; c <= 3; c++){if(r <= HEIGHT && block[r][c] != 0)tempBoard[r+j][c+k] = block[r][c];   }    }    for(int r = 0; r <= 13; r++){for(int c = 0; c <= 9; c++){gameBoard[r][c] = tempBoard[r][c];   }    }    for(int r = 0; r <= 13; r++){for(int c = 0; c <= 9; c++){tempBoard[r][c] = 0;   }    }    for(int r = 0; r <= 13; r++){for(int c = 0; c <= 9; c++){tempBoard[r][c] = gameBoard[r][c];   }    }   j++;}void draw(){    blit(background, buffer, 0, 0, 0, 0, 1024, 768);    for(int r = 0; r <= HEIGHT; r++){for(int c = 0; c <= WIDTH; c++){    if(gameBoard[r][c] == 1) blit(gBlock, buffer, 0, 0, (50*c)+175, r*50, 50, 50);   }}    blit(buffer, screen, 0, 0, 0, 0, 1024, 768);};Quote:Original post by klee1This is because what's happening is that when you call your move blocks method, the block is getting placed at the bottom of the screen.Consider a 5x3 matrix:011110000000000When you call the method it will start at r=0, but nothing will happen because it will fail the r>0 part of your if statement.r=1, every place that there is a block above, that block will be removed, and the placed on the line below.  Your matrix now looks like this:000000111100000r=2, the same move will occur, and your matrix will look like this:000000000001111So as you can see, in one call of your method, moveBlocks(), a block will always move to the bottom of the screen.  You will also have other problems:Consider:011100010000000at r=1, the code will generate:000000111000000So we have lost a part of the tetromino.Also, with this current method, there will be no way to lock blocks at the bottom of the screen, the blocks will always move downwards, and won't stay in place like they should in a classic game of tetris.So your current method of moving the blocks simply will not work.By reversing the order which you read i.e. for(r=BOTTOM; r >= TOP; r--) assuming BOTTOM is the bottom of the board and TOP is the top and TOP < BOTTOM.  Going back to previous examples.First of:01111 -> 0000000000 -> 0111100000 -> 00000This would be because the bottom row has nothing, and will skip until it reaches the top, which it moves down one.01110 -> 0000000100 -> 0111000000 -> 00100It would move the little bit on the bottom of the piece before it moves the upper rows, allow no lost of pieces.In my examples, board[x][y] where y = 0 is the top, and y = 2 is the bottom.   ;Quote:Original post by dragonhawk360By reversing the order which you read i.e. for(r=BOTTOM; r >= TOP; r--) assuming BOTTOM is the bottom of the board and TOP is the top and TOP < BOTTOM.  Going back to previous examples.This is true, but there are still problems with this form of implementation.  Namely, that there will be other pieces on the board, and we are not supposed to shift any of them other than the four that we are interested in.So, were you to still use that method of shifting all of the pieces down you would need to have 3 matrices all of the size of the board.  The first one would have all of the locked pieces.  The second would have just the active piece, and the third would be the combination of the two.So you would have something like this:  00000&nbsp  01110&nbsp 01110  00000&nbsp  00100&nbsp 00100  00001   +   00000   =  00001  00001&nbsp  00000&nbsp 00001  00011&nbsp  00000&nbsp 00011You would then use your draw method to draw the third matrix.When you determined that the piece can not go further, you would superimpose it from the second matrix to the first, and then clear the second and place a new piece in it:  00000  &nbsp 00000  ->  00000 &nbsp 01110  00000  &nbsp 00000  ->  00000  &nbsp 00010  00001  &nbsp 00000  ->  00001 &nbsp 00000  00001  &nbsp 01110  ->  01111 &nbsp 00000  00011 ,  00100  ->  00111 ,  00000However, I still have my misgivings about this because you would have to store at least 2 matrices(and maybe a combination one)  where using my method you would only have to use one matrix and an array of 4 ints.   ;Quote:Original post by klee1First off, I would move all of the drawing functions back into the draw() method.  It is better design to have all of your drawing functions separate from your actual game code.  The one that you had in your original post seems to work fine.  That way, the moveBlock() function only concerns itself with moving blocks and not with drawing any to the screen.That being said, I think that the idea of having an array of positions of the block that is currently moving is a good one.  Here are its advantages:1)You can move only the block that is currently active (not all of the blocks)2)If done properly makes collision detection much easierSo you could have an array of ints that contains the positions of each part of the block, and then in your moveBlock method you can just:1)delete the old block(zeroing out the matrix at the positions of the currentBlock)2)increment the y position of each part of the block.3)Check if all of the new block positions are valid(not more then the height of the array, or in a spot that's already taken, in which case you would move the block back up and lock it)4)redraw the block in its new location (placing 1s in the gameBoard at the positions of the current block).I like your idea and I am still having trouble.  However, I'm not sure I understand what you said in the above statement.[Edited by - DeFessler on May 10, 2009 2:30:27 PM]