Raylib-Tetris: Maps And Rotation
Written on August 30th, 2020 by Rangga GunartoRaylib-Tetris: Maps? What Are Those? (AUG 31 EXT)
Remember when I said that I changed the character int he array from an ‘x’ to another letter to stop it from moving? Well I have decided that I want to assign each template to a character which would eventually replace the ‘x’ according to the tetromino name after it had hit the bottom of the playGrid. Now I had no idea how I would assign the templates in TEMPLATES_ARR
to a character. My brother had told me there was a way by using ‘maps’. Initially, I was confused at first wondering how to use maps and what they looked like, after looking through forum sites and StackOverflow and found out how it looked like and how to use it, and in the end it was pretty simple.
Assigning Templates To Characters
First, I had to make the function (maps function) understand what I was assigning:
std::map<TEMPLATES, char> TEMPLATE_CHAR_MAP{
{TEMPLATES::I_BLOCK_TEMPLATE, 'i'},
{TEMPLATES::J_BLOCK_TEMPLATE, 'j'},
{TEMPLATES::L_BLOCK_TEMPLATE, 'l'},
{TEMPLATES::O_BLOCK_TEMPLATE, 'o'},
{TEMPLATES::S_BLOCK_TEMPLATE, 's'},
{TEMPLATES::T_BLOCK_TEMPLATE, 't'},
{TEMPLATES::Z_BLOCK_TEMPLATE, 'z'},
{TEMPLATES::INVALID, 'f'}
};
This map would assign the templates for TEMPLATES_ARR
to a char, e.g I_BLOCK_TEMPLATE
would be assigned to the character ‘i’. So previously when I had the bottom grid detection do this at the end: playGrid[i][j] = 'z';
I changed it to: playGrid[i][j] = TEMPLATE_CHAR_MAP;
, so once the ‘x’ hits the bottom, depending on the template it would change the character ‘x’ to its assigned character according to the template.
Now, instead of assigning the color of the template inside TEMPLATES_ARR
I would just need a map to assign the assigned characters to the color they would be assigned to. Still with me?
std::map<char, Color> BLOCK_COLOR_MAP {
{'i', SKYBLUE},
{'j', DARKBLUE},
{'l', ORANGE},
{'o', YELLOW},
{'s', GREEN},
{'t', PURPLE},
{'z', RED}
};
This piece of code would help when spawning the tetromino block to its template.
Tasks That Have Been Completed
- Making blocks
- Making them fall automatically
- Making templates for all tetrominos
- Make them spawn automatically onto the playGrid
- Basic wall hit detection
- Assign Blocks To Characters
- Assign Templates To Its Colour
- Block to block hit detection
- Basic Movement
- Rotation
- Basic Aesthetics
- Show next block
- Make a ‘hold block’ function
- Show held block
- Points system
- Special Effects?
- Restart, Game Over
- Make a ‘Press Space To Start’ text before starting the game
Underestimating Rotation
Due to the other basic movements being easy to make I thought it would be easy too, but nope. I tried multiple attempts but I couldn’t a solution, so I searched up the formula on how tetromino blocks were rotated, I found my answer shortly but now all I had to do was make it part of a function that could be called. Admittedly I did need some help from my brother.
void rotateFalling(char grid[24][10]) {
bool canRotate = true;
int pXMin = 23, pYMin = 9, pXMax = 0, pYMax = 0;
for (int i = 23; i >= 0; i--)
for (int j = 9; j >= 0; j--)
if (grid[i][j] == 'x') {
pXMin = std::min(pXMin, i);
pXMax = std::max(pXMax, i);
pYMin = std::min(pYMin, j);
pYMax = std::max(pYMax, j);
}
float pX = roundf((float) (pXMin + pXMax) / 2);
float pY = roundf((float) (pYMin + pYMax) / 2);
char gridAlt[24][10] = { 0 };
for (int i = 23; i >= 0; i--)
for (int j = 9; j >= 0; j--)
if (grid[i][j] == 'x') {
if (i == pX && j == pY) {
gridAlt[i][j] = 'x';
continue;
}
float newI, newJ;
newI = pX - (j - pY);
newJ = (pY + i) - pX;
if ((int)roundf(newI) < 0 || (int)roundf(newI) > 23 || (int)roundf(newJ) < 0 || (int)roundf(newJ) > 9)
return;
gridAlt[(int) roundf(newI)][(int) roundf(newJ)] = 'x';
}
for (int i = 23; i >= 0; i--)
for (int j = 9; j >= 0; j--)
if (grid[i][j] == 'x') {
grid[i][j] = ' ';
}
for (int i = 23; i >= 0; i--)
for (int j = 9; j >= 0; j--)
if (gridAlt[i][j] == 'x') {
grid[i][j] = 'x';
}
}
This looks quite complicated but i’ll run through the basics. First, there is a boolean variable which would indicate if it was possible to rotate the piece, then I did a few calculations for positions x max, position x min etc. Then, I would the the actual code to detect if they could rotate or not (I had a few instances where the function corrupted because I didnt make the hit detection properly, it is now fixed), this ‘gridAlt’ would basically act as a ‘fake’ grid to the rotation then put it on the actual playGrid by overwriting the ‘x’ on the playGrid with the information in altGrid.
Tasks That Have Been Completed
- Making blocks
- Making them fall automatically
- Making templates for all tetrominos
- Make them spawn automatically onto the playGrid
- Basic wall hit detection
- Assign Blocks To Characters
- Assign Templates To Its Colour
- Block to block hit detection
- Basic Movement
- Rotation
- Basic Aesthetics
- Show next block
- Make a ‘hold block’ function
- Show held block
- Points system
- Special Effects?
- Restart, Game Over
- Make a ‘Press Space To Start’ text before starting the game
Making Blocks Actual Blocks
So, we can spawn blocks, we can move the blocks and we rotate them BUT I’ve forgot to implement block to block hit detection, blocks have top to top collision due to the ‘x’ character changing (I have changed the hit detection, it is not the same as I mentioned in my first devlog) but not side to side collision, so when a block goes to the left or to the right and there’s a block it just overwrites the already fallen block, so here’s how I did it:
bool collision = false;
for (int i = 23; i >= 0; i--) {
// check for collision
for (int j = 0; j < 10; j++)
{
if (playGrid[i][j] == 'x') {
if (i == 23 || (playGrid[i + 1][j] != ' ' && playGrid[i + 1][j] != 'x')) {
collision = true;
goto col;
}
}
}
}
So here I checked the rows from bottom to top and checked the columns left to right, then there is a if statement checking if there is an X in the playGrid. If there was an X it would check if the row it was in/next to did not have a space or an X, this would then change the boolean to true. Then, I did a ‘goto’ to col which is the code below:
col:
if (collision) {
droppingSameBlock = false;
for (int i = 23; i >= 0; i--)
for (int j = 0; j < 10; j++)
{
if (playGrid[i][j] == 'x') {
playGrid[i][j] = TEMPLATE_CHAR_MAP[curTemplate];
}
}
So essentially, this piece of code which would change the boolean droppingSameBlock (a boolean that is made earlier that would state the user is controlling the same block), then it would check all the rows for ‘x’ then change them into their specified char from the map I made.
List Of Tasks Completed
- Making blocks
- Making them fall automatically
- Making templates for all tetrominos
- Make them spawn automatically onto the playGrid
- Basic wall hit detection
- Assign Blocks To Characters
- Assign Templates To Its Colour
- Block to block hit detection
- Basic Movement
- Rotation
- Basic Aesthetics
- Show next block
- Make a ‘hold block’ function
- Show held block
- Points system
- Special Effects?
- Restart, Game Over
- Make a ‘Press Space To Start’ text before starting the game