Tetris Clones: Movement & Collision

Recommended Posts

clockwise    167
OK, I've been wanting to write my own(tada!) tetris clone fore awhile now but when I try, I cant seem to figure out exactly what the best way to move the blocks around is and how to do collision on them. Basically I have the idea to use a 4x4 array which will suffice for each piece. Example: 0000 1000 0000 0000 0100 1000 0110 0110 1110 1000 0011 0110 0000 1000 0000 0000 The hard part comes in when I try to figure out how to keep track of it inside the game board(also an array). Then doing collision, since I store my blocks as arrays I'm thinking I'd have to check each indice against the board to figure out if its touch something, and is inside the boundaries. Once I get this part figured out I'm sure I can write the rest with no trouble, but just when I sit down to try and figure it out, I cant seem to come up with a solution that I can translate into code. How did you guys do it? I just think I need a little direction thats all. Thanks P.S. I haven't written any code yet this time, I'm just brainstorming, and searching for ideas.

Share on other sites
Schultz    140
Well, you have your array for the block, and an array for the game board. In addition you need to keep track of the position and rotation of the current active block. When it's time to move the block one step down, check the blocks array against the boards array, and if it collides, add the active block to the board, move it back up and change the type.

Something like this should work for detecting the collision:

activeblock.y --;
for(xl = 0; xl < 4; xl++){
for(yl = 0; yl < 4; yl++){
if(activeblock[xl][yl] && board[activeblock.x + xl][activeblock.y + yl]) collide();
}}

if it collides, set the correct blocks on the board to true and reset the active block.

Share on other sites
clockwise    167
Thanks schultz, I'm gonna try and whip up a demo for a little more
visual.

Share on other sites
Fred304    382
A neat trick is to make the board huge enough so you won't have to check if the stone lies outside of the board. My board usually looks something like this:
00000000000000000000000000000000000000000000000000000000000000000010000000000100001000000000010000100000000001000010000000000100001000000000010000100000000001000010000000000100001000000000010000100000000001000010000000000100001000000000010000100000000001000010000000000100001000000000010000100000000001000010000000000100001000000000010000100000000001000010000000000100001000000000010000111111111111000000000000000000000000000000000000000000000000000000000000000000

This way, any block will collide with the border before it can get out of the board, thus no index checking required.

Another hint I can give you is to use another data structure for your stones.
If you store them as a 4x4 matrix you have to do 16 collision tests, because theoretically any of the 16 entries could be set to 1 (allowing for grotesquely formed blocks). When you look at the nested for loops, it seems like you are "searching for the 1s", yet you already know precisely where they are and that there's exactly four of them. So why not simply store the 4 coordinates?

In my previous tetris clone, I stored the data for the O block as follows:
const char stone[] = {0x11, 0x12, 0x21, 0x22}; // of course there are more stones, this is just an example

0x21 means y is 2 and x is 1. Now remember the board being a little larger than the visible 10 blocks? It's no accident I chose 16 as the width, because this way you can simply use each of the four stone[] values as an index into the board after adding the the current coordinates to it. That's how my collision method looked like:

int collision(){    int res = 0;    const int current = current_y<<4 + current_x;    for (int i=0; i<4; i++)    {        res |= board[current + stone[i]];    }    return res;}

Of course you can also unroll the loop quite easily:

int collision(){    const int current = current_y<<4 + current_x;    return board[current + stone[0]]           |board[current + stone[1]]           |board[current + stone[2]]           |board[current + stone[3]];}

I think this is a great example why you should choose the appropriate data structure carefully. Just because every stone fits in a 4x4 matrix it does not mean this is the best solution to store them.

Share on other sites
clockwise    167
Hey! I never thought about doing it that way, some good tips. The only problem is somehow I have survived as a programmer without ever learning hex or bit operations(was going to ask about that in another thread), where might I learn about those things so I can use these techniques?

Share on other sites
Fred304    382
Quote:
 Original post by clockwiseI have survived as a programmer without ever learning hex or bit operations

Hex is just another way to present your numbers. Additionally to the ten digits you already know from the decimal system there are six more digits: A, B, C, D, E and F.

Thus, the first sixteen numbers in hex are:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F

The same numbers in decimal are:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15

In order to mark a number as hex you usually put 0x or \$ in front of it (or h at the end).
Here is a table for the first 256 numbers:

     0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f0x00    0    1    2    3    4    5    6    7    8    9   10   11   12   13   14   150x10   16   17   18   19   20   21   22   23   24   25   26   27   28   29   30   310x20   32   33   34   35   36   37   38   39   40   41   42   43   44   45   46   470x30   48   49   50   51   52   53   54   55   56   57   58   59   60   61   62   630x40   64   65   66   67   68   69   70   71   72   73   74   75   76   77   78   790x50   80   81   82   83   84   85   86   87   88   89   90   91   92   93   94   950x60   96   97   98   99  100  101  102  103  104  105  106  107  108  109  110  1110x70  112  113  114  115  116  117  118  119  120  121  122  123  124  125  126  1270x80  128  129  130  131  132  133  134  135  136  137  138  139  140  141  142  1430x90  144  145  146  147  148  149  150  151  152  153  154  155  156  157  158  1590xa0  160  161  162  163  164  165  166  167  168  169  170  171  172  173  174  1750xb0  176  177  178  179  180  181  182  183  184  185  186  187  188  189  190  1910xc0  192  193  194  195  196  197  198  199  200  201  202  203  204  205  206  2070xd0  208  209  210  211  212  213  214  215  216  217  218  219  220  221  222  2230xe0  224  225  226  227  228  229  230  231  232  233  234  235  236  237  238  2390xf0  240  241  242  243  244  245  246  247  248  249  250  251  252  253  254  255

To get the right hexadecimal representation, you simply add what's in the first column of the corresponding line and the first line of the column. For example, 200 is 0xc0+0x08 = 0xc8.

Since 16 is a power of 2, every hex digit can be represented by four binary digits:

0x0 = 0000b0x1 = 0001b0x2 = 0010b0x3 = 0011b0x4 = 0100b0x5 = 0101b0x6 = 0110b0x7 = 0111b0x8 = 1000b0x9 = 1001b0xA = 1010b0xB = 1011b0xC = 1100b0xD = 1101b0xE = 1110b0xF = 1111b

I assume you know how to add numbers in decimal with pen and paper. Try the same in hex.

What is 5+5, 6+A, F+F, 2C+D4 ? What is 100-2?