Tetris Clones: Movement & Collision
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.
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.
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.
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:
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:
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:
Of course you can also unroll the loop quite easily:
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.
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]; } 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.
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?
Quote:Original post by clockwise
I 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?
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement