To build a tetris game using tutorials
found a tetris tutorial
is a tile-matching puzzle video game originally designed and programmed by Alexey Pajitnov in the Soviet Union. It was released on June 6, 1984,[1] while he was working for the Dorodnicyn Computing Centre of the Academy of Science of the USSR in Moscow.[2] He derived its name from the Greek numerical prefix tetra- (all of the game's pieces contain four segments) and tennis, Pajitnov's favorite sport.[3][4]
It is also the first entertainment software to be exported from the USSR to the US and published by Spectrum HoloByte for Commodore 64 and IBM PC. The Tetris game is a popular use of tetrominoes, the four-element special case of polyominoes. Polyominoes have been used in popular puzzles since at least 1907, and the name was given by the mathematician Solomon W. Golomb in 1953. However, even the enumeration of pentominoes is dated to antiquity.
Defines.h
#pragma once // Window related defines // #define WINDOW_WIDTH 300 #define WINDOW_HEIGHT 400 #define WINDOW_CAPTION "Falling Blocks" // Game related defines // #define FRAMES_PER_SECOND 30 #define FRAME_RATE 1000/FRAMES_PER_SECOND #define GAME_AREA_LEFT 53 #define GAME_AREA_RIGHT 251 #define GAME_AREA_BOTTOM 298 #define NUM_LEVELS 5 #define POINTS_PER_LINE 525 #define POINTS_PER_LEVEL 6300 #define INITIAL_SPEED 60 #define SPEED_CHANGE 10 #define SLIDE_TIME 15 #define SQUARES_PER_ROW 10 #define SQUARE_MEDIAN 10 // Starting position of the focus block // #define BLOCK_START_X 151 #define BLOCK_START_Y 59 // Location on game screen for displaying... // #define LEVEL_RECT_X 42 // current level #define LEVEL_RECT_Y 320 #define SCORE_RECT_X 42 // current score #define SCORE_RECT_Y 340 #define NEEDED_SCORE_RECT_X 42 // score needed for next level #define NEEDED_SCORE_RECT_Y 360 #define NEXT_BLOCK_CIRCLE_X 214 // next block in line to be focus block #define NEXT_BLOCK_CIRCLE_Y 347 // Locations within bitmap of background screens // #define LEVEL_ONE_X 0 #define LEVEL_ONE_Y 0 #define LEVEL_TWO_X 300 #define LEVEL_TWO_Y 0 #define LEVEL_THREE_X 300 #define LEVEL_THREE_Y 0 #define LEVEL_FOUR_X 0 #define LEVEL_FOUR_Y 396 #define LEVEL_FIVE_X 300 #define LEVEL_FIVE_Y 396 // Location within bitmap of colored squares // #define RED_SQUARE_X 600 #define RED_SQUARE_Y 400 #define PURPLE_SQUARE_X 620 #define PURPLE_SQUARE_Y 400 #define GREY_SQUARE_X 640 #define GREY_SQUARE_Y 400 #define BLUE_SQUARE_X 660 #define BLUE_SQUARE_Y 400 #define GREEN_SQUARE_X 680 #define GREEN_SQUARE_Y 400 #define BLACK_SQUARE_X 700 #define BLACK_SQUARE_Y 400 #define YELLOW_SQUARE_X 720 #define YELLOW_SQUARE_Y 400
enums.h
#pragma once enum BlockType { SQUARE_BLOCK, T_BLOCK, L_BLOCK, BACKWARDS_L_BLOCK, STRAIGHT_BLOCK, S_BLOCK, BACKWARDS_S_BLOCK }; enum Direction { LEFT, RIGHT, DOWN };
cSquare.h
#pragma once #include "cSquare.h" class cBlock { private: int m_CenterX; int m_CenterY; BlockType m_Type; cSquare* m_Squares[4]; public: cBlock(int x, int y, SDL_Surface* bitmap, BlockType type) : m_CenterX(x), m_CenterY(y), m_Type(type) { for (int i=0; i<4; i++) { m_Squares[i] = NULL; } SetupSquares(x, y, bitmap); } void SetupSquares(int x, int y, SDL_Surface* bitmap) { m_CenterX = x; m_CenterY = y; // Make sure that any current squares are deleted // for (int i=0; i<4; i++) { if (m_Squares[i]) delete m_Squares[i]; } switch (m_Type) { case SQUARE_BLOCK: { m_Squares[0] = new cSquare(x - SQUARE_MEDIAN, y - SQUARE_MEDIAN, bitmap, m_Type); m_Squares[1] = new cSquare(x - SQUARE_MEDIAN, y + SQUARE_MEDIAN, bitmap, m_Type); m_Squares[2] = new cSquare(x + SQUARE_MEDIAN, y - SQUARE_MEDIAN, bitmap, m_Type); // Lower right // m_Squares[3] = new cSquare(x + SQUARE_MEDIAN, y + SQUARE_MEDIAN, bitmap, m_Type); } break; case T_BLOCK: { // Top // m_Squares[0] = new cSquare(x + SQUARE_MEDIAN, y - SQUARE_MEDIAN, bitmap, m_Type); // Middle // m_Squares[1] = new cSquare(x + SQUARE_MEDIAN, y + SQUARE_MEDIAN, bitmap, m_Type); // Left // m_Squares[2] = new cSquare(x - SQUARE_MEDIAN, y + SQUARE_MEDIAN, bitmap, m_Type); // Right // m_Squares[3] = new cSquare(x + (SQUARE_MEDIAN * 3), y + SQUARE_MEDIAN, bitmap, m_Type); } break; case L_BLOCK: { m_Squares[0] = new cSquare(x - SQUARE_MEDIAN, y - SQUARE_MEDIAN, bitmap, m_Type); m_Squares[1] = new cSquare(x - SQUARE_MEDIAN, y + SQUARE_MEDIAN, bitmap, m_Type); m_Squares[2] = new cSquare(x - SQUARE_MEDIAN, y + (SQUARE_MEDIAN * 3), bitmap, m_Type); m_Squares[3] = new cSquare(x + SQUARE_MEDIAN, y + (SQUARE_MEDIAN * 3), bitmap, m_Type); } break; case BACKWARDS_L_BLOCK: { // | // m_Squares[0] = new cSquare(x + SQUARE_MEDIAN, y - SQUARE_MEDIAN, bitmap, m_Type); // | // m_Squares[1] = new cSquare(x + SQUARE_MEDIAN, y + SQUARE_MEDIAN, bitmap, m_Type); // _| // m_Squares[2] = new cSquare(x + SQUARE_MEDIAN, y + (SQUARE_MEDIAN * 3), bitmap, m_Type); // __ // m_Squares[3] = new cSquare(x - SQUARE_MEDIAN, y + (SQUARE_MEDIAN * 3), bitmap, m_Type); } break; case STRAIGHT_BLOCK: { // Top // m_Squares[0] = new cSquare(x + SQUARE_MEDIAN, y - (SQUARE_MEDIAN * 3), bitmap, m_Type); m_Squares[1] = new cSquare(x + SQUARE_MEDIAN, y - SQUARE_MEDIAN, bitmap, m_Type); m_Squares[2] = new cSquare(x + SQUARE_MEDIAN, y + SQUARE_MEDIAN, bitmap, m_Type); m_Squares[3] = new cSquare(x + SQUARE_MEDIAN, y + (SQUARE_MEDIAN * 3), bitmap, m_Type); // Bottom // } break; case S_BLOCK: { // Top right // m_Squares[0] = new cSquare(x + (SQUARE_MEDIAN * 3), y - SQUARE_MEDIAN, bitmap, m_Type); // Top middle // m_Squares[1] = new cSquare(x + SQUARE_MEDIAN, y - SQUARE_MEDIAN, bitmap, m_Type); // Bottom middle // m_Squares[2] = new cSquare(x + SQUARE_MEDIAN, y + SQUARE_MEDIAN, bitmap, m_Type); // Bottom left // m_Squares[3] = new cSquare(x - SQUARE_MEDIAN, y + SQUARE_MEDIAN, bitmap, m_Type); } break; case BACKWARDS_S_BLOCK: { // Top left // m_Squares[0] = new cSquare(x - SQUARE_MEDIAN, y - SQUARE_MEDIAN, bitmap, m_Type); // Top middle // m_Squares[1] = new cSquare(x + SQUARE_MEDIAN, y - SQUARE_MEDIAN, bitmap, m_Type); // Bottom middle // m_Squares[2] = new cSquare(x + SQUARE_MEDIAN, y + SQUARE_MEDIAN, bitmap, m_Type); // Bottom right // m_Squares[3] = new cSquare(x + (SQUARE_MEDIAN * 3), y + SQUARE_MEDIAN, bitmap, m_Type); } break; } } void Draw(SDL_Surface* Window) { for (int i=0; i<4; i++) { m_Squares[i]->Draw(Window); } } void Move(Direction dir) { switch (dir) { case LEFT: { m_CenterX -= SQUARE_MEDIAN * 2; } break; case RIGHT: { m_CenterX += SQUARE_MEDIAN * 2; } break; case DOWN: { m_CenterY += SQUARE_MEDIAN*2; } break; } for (int i=0; i<4; i++) { m_Squares[i]->Move(dir); } } void Rotate() { int x1, y1, x2, y2; for (int i=0; i<4; i++) { x1 = m_Squares[i]->GetCenterX(); y1 = m_Squares[i]->GetCenterY(); x1 -= m_CenterX; y1 -= m_CenterY; x2 = - y1; y2 = x1; x2 += m_CenterX; y2 += m_CenterY; m_Squares[i]->SetCenterX(x2); m_Squares[i]->SetCenterY(y2); } } int* GetRotatedSquares() { int* temp_array = new int[8]; int x1, y1, x2, y2; for (int i=0; i<4; i++) { x1 = m_Squares[i]->GetCenterX(); y1 = m_Squares[i]->GetCenterY(); x1 -= m_CenterX; y1 -= m_CenterY; x2 = - y1; y2 = x1; x2 += m_CenterX; y2 += m_CenterY; temp_array[i*2] = x2; temp_array[i*2+1] = y2; } return temp_array; } cSquare** GetSquares() { return m_Squares; } };
main.cpp
#pragma comment(lib, "SDL.lib") #pragma comment(lib, "SDLmain.lib") #pragma comment(lib, "SDL_TTF.lib") #include <stack> #include <vector> #include "time.h" #include "math.h" #include "SDL.h" #include "SDL_TTF.h" #include "Defines.h" #include "Enums.h" #include "cBlock.h" using namespace std; struct StateStruct { void (*StatePointer)(); }; // Global data // stack<StateStruct> g_StateStack; SDL_Surface* g_Bitmap = NULL; SDL_Surface* g_Window = NULL; SDL_Event g_Event; int g_Timer; integer cBlock* g_FocusBlock = NULL; cBlock* g_NextBlock = NULL; block vector<cSquare*> g_OldSquares; block int g_Score = 0; int g_Level = 1; int g_FocusBlockSpeed = INITIAL_SPEED; // Init and Shutdown functions // void Init(); void Shutdown(); // Functions to handle the states of the game // void Menu(); void Game(); void Exit(); void GameWon(); void GameLost(); void DrawBackground(); void ClearScreen(); void DisplayText(string text, int x, int y, int size, int fR, int fG, int fB, int bR, int bG, int bB); void HandleMenuInput(); void HandleGameInput(); void HandleExitInput(); void HandleWinLoseInput(); bool CheckEntityCollisions(cSquare* square, Direction dir); bool CheckWallCollisions(cSquare* square, Direction dir); bool CheckEntityCollisions(cBlock* block, Direction dir); bool CheckWallCollisions(cBlock* block, Direction dir); bool CheckRotationCollisions(cBlock* block); void CheckWin(); void CheckLoss(); void HandleBottomCollision(); void ChangeFocusBlock(); int CheckCompletedLines(); int main(int argc, char **argv) { Init(); while (!g_StateStack.empty()) { g_StateStack.top().StatePointer(); } Shutdown(); return 0; } void Init() { SDL_Init( SDL_INIT_VIDEO | SDL_INIT_TIMER); g_Window = SDL_SetVideoMode(WINDOW_WIDTH, WINDOW_HEIGHT, 0, SDL_ANYFORMAT); SDL_WM_SetCaption(WINDOW_CAPTION, 0); g_Timer = SDL_GetTicks(); g_Bitmap = SDL_LoadBMP("data/FallingBlocks.bmp"); // Seed our random number generator // srand( time(0) ); // Initialize blocks and set them to their proper locations. // g_FocusBlock = new cBlock(BLOCK_START_X, BLOCK_START_Y, g_Bitmap, (BlockType)(rand()%7)); g_NextBlock = new cBlock(NEXT_BLOCK_CIRCLE_X, NEXT_BLOCK_CIRCLE_Y, g_Bitmap, (BlockType)(rand()%7)); StateStruct state; state.StatePointer = Exit; g_StateStack.push(state); state.StatePointer = Menu; g_StateStack.push(state); // Initialize the true type font library // TTF_Init(); } void Shutdown() { // Shutdown the true type font library // TTF_Quit(); // Free our surfaces // SDL_FreeSurface(g_Bitmap); SDL_FreeSurface(g_Window); cSquare** temp_array_1 = g_FocusBlock->GetSquares(); cSquare** temp_array_2 = g_NextBlock->GetSquares(); // Delete our blocks // delete g_FocusBlock; delete g_NextBlock; // Delete the temporary arrays of squares // for (int i=0; i<4; i++) { delete temp_array_1[i]; delete temp_array_2[i]; } // Delete the squares that are in the game area // for (int i=0; i<g_OldSquares.size(); i++) { delete g_OldSquares[i]; } // Tell SDL to shutdown and free any resources it was using // SDL_Quit(); } void Menu() { if ( (SDL_GetTicks() - g_Timer) >= FRAME_RATE ) { HandleMenuInput(); ClearScreen(); DisplayText("Start (G)ame", 120, 120, 12, 255, 255, 255, 0, 0, 0); DisplayText("(Q)uit Game", 120, 150, 12, 255, 255, 255, 0, 0, 0); SDL_UpdateRect(g_Window, 0, 0, 0, 0); g_Timer = SDL_GetTicks(); } } void Game() { static int force_down_counter = 0; static int slide_counter = SLIDE_TIME; if ( (SDL_GetTicks() - g_Timer) >= FRAME_RATE ) { HandleGameInput(); force_down_counter++; if (force_down_counter >= g_FocusBlockSpeed) { // Always check for collisions before moving anything // if ( !CheckWallCollisions(g_FocusBlock, DOWN) && !CheckEntityCollisions(g_FocusBlock, DOWN) ) { g_FocusBlock->Move(DOWN); // move the focus block force_down_counter = 0; // reset our counter } } if ( CheckWallCollisions(g_FocusBlock, DOWN) || CheckEntityCollisions(g_FocusBlock, DOWN) ) { slide_counter--; } else { slide_counter = SLIDE_TIME; } if (slide_counter == 0) { slide_counter = SLIDE_TIME; HandleBottomCollision(); } // Make sure nothing from the last frame is still drawn. // ClearScreen(); // Draw the background // DrawBackground(); // Draw the focus block and next block. // g_FocusBlock->Draw(g_Window); g_NextBlock->Draw(g_Window); // Draw the old squares. // for (int i=0; i < g_OldSquares.size(); i++) { g_OldSquares[i]->Draw(g_Window); } // Draw the text for the current level, score, and needed score. // char temp[256]; string score = "Score: "; itoa(g_Score, temp, 10); score.append( temp ); string nextscore = "Needed Score: "; itoa(g_Level*POINTS_PER_LEVEL, temp, 10); nextscore.append(temp); string level = "Level: "; itoa(g_Level, temp, 10); level.append(temp); DisplayText(score, SCORE_RECT_X, SCORE_RECT_Y, 8, 0, 0, 0, 255, 255, 255); DisplayText(nextscore, NEEDED_SCORE_RECT_X, NEEDED_SCORE_RECT_Y, 8, 0, 0, 0, 255, 255, 255); DisplayText(level, LEVEL_RECT_X, LEVEL_RECT_Y, 8, 0, 0, 0, 255, 255, 255); SDL_UpdateRect(g_Window, 0, 0, 0, 0); g_Timer = SDL_GetTicks(); } } void Exit() { if ( (SDL_GetTicks() - g_Timer) >= FRAME_RATE ) { HandleExitInput(); // Make sure nothing from the last frame is still drawn. // ClearScreen(); DisplayText("Quit Game (Y or N)?", 100, 150, 12, 255, 255, 255, 0, 0, 0); SDL_UpdateRect(g_Window, 0, 0, 0, 0); g_Timer = SDL_GetTicks(); } } // Display a victory message. // void GameWon() { if ( (SDL_GetTicks() - g_Timer) >= FRAME_RATE ) { HandleWinLoseInput(); ClearScreen(); DisplayText("You Win!!!", 100, 120, 12, 255, 255, 255, 0, 0, 0); DisplayText("Quit Game (Y or N)?", 100, 140, 12, 255, 255, 255, 0, 0, 0); SDL_UpdateRect(g_Window, 0, 0, 0, 0); g_Timer = SDL_GetTicks(); } } // Display a game over message. // void GameLost() { if ( (SDL_GetTicks() - g_Timer) >= FRAME_RATE ) { HandleWinLoseInput(); ClearScreen(); DisplayText("You Lose.", 100, 120, 12, 255, 255, 255, 0, 0, 0); DisplayText("Quit Game (Y or N)?", 100, 140, 12, 255, 255, 255, 0, 0, 0); SDL_UpdateRect(g_Window, 0, 0, 0, 0); g_Timer = SDL_GetTicks(); } } // This function draws the background // void DrawBackground() { SDL_Rect source; switch (g_Level) { case 1: { SDL_Rect temp = { LEVEL_ONE_X, LEVEL_ONE_Y, WINDOW_WIDTH, WINDOW_HEIGHT }; source = temp; } break; case 2: { SDL_Rect temp = { LEVEL_TWO_X, LEVEL_TWO_Y, WINDOW_WIDTH, WINDOW_HEIGHT }; source = temp; } break; case 3: { SDL_Rect temp = { LEVEL_THREE_X, LEVEL_THREE_Y, WINDOW_WIDTH, WINDOW_HEIGHT }; source = temp; } break; case 4: { SDL_Rect temp = { LEVEL_FOUR_X, LEVEL_FOUR_Y, WINDOW_WIDTH, WINDOW_HEIGHT }; source = temp; } break; case 5: { SDL_Rect temp = { LEVEL_FIVE_X, LEVEL_FIVE_Y, WINDOW_WIDTH, WINDOW_HEIGHT }; source = temp; } break; } SDL_Rect destination = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT }; SDL_BlitSurface(g_Bitmap, &source, g_Window, &destination); } void ClearScreen() { SDL_FillRect(g_Window, 0, 0); } void DisplayText(string text, int x, int y, int size, int fR, int fG, int fB, int bR, int bG, int bB) { TTF_Font* font = TTF_OpenFont("arial.ttf", size); SDL_Color foreground = { fR, fG, fB}; // text color SDL_Color background = { bR, bG, bB }; // color of what's behind the text SDL_Surface* temp = TTF_RenderText_Shaded(font, text.c_str(), foreground, background); SDL_Rect destination = { x, y, 0, 0 }; SDL_BlitSurface(temp, NULL, g_Window, &destination); SDL_FreeSurface(temp); TTF_CloseFont(font); } void HandleMenuInput() { if ( SDL_PollEvent(&g_Event) ) { if (g_Event.type == SDL_QUIT) { while (!g_StateStack.empty()) { g_StateStack.pop(); } return; } // Handle keyboard input here // if (g_Event.type == SDL_KEYDOWN) { if (g_Event.key.keysym.sym == SDLK_ESCAPE) { g_StateStack.pop(); return; // this state is done, exit the function } // Quit // if (g_Event.key.keysym.sym == SDLK_q) { g_StateStack.pop(); return; // game is over, exit the function } // Start Game // if (g_Event.key.keysym.sym == SDLK_g) { StateStruct temp; temp.StatePointer = Game; g_StateStack.push(temp); return; // this state is done, exit the function } } } } void HandleGameInput() { static bool down_pressed = false; static bool left_pressed = false; static bool right_pressed = false; if ( SDL_PollEvent(&g_Event) ) { if (g_Event.type == SDL_QUIT) { while (!g_StateStack.empty()) { g_StateStack.pop(); } return; // game is over, exit the function } // Handle keyboard input here // if (g_Event.type == SDL_KEYDOWN) { if (g_Event.key.keysym.sym == SDLK_ESCAPE) { g_StateStack.pop(); return; // this state is done, exit the function } if (g_Event.key.keysym.sym == SDLK_UP) { // Check collisions before rotating // if (!CheckRotationCollisions(g_FocusBlock)) { g_FocusBlock->Rotate(); } } if (g_Event.key.keysym.sym == SDLK_LEFT) { left_pressed = true; } if (g_Event.key.keysym.sym == SDLK_RIGHT) { right_pressed = true; } if (g_Event.key.keysym.sym == SDLK_DOWN) { down_pressed = true; } } if (g_Event.type == SDL_KEYUP) { if (g_Event.key.keysym.sym == SDLK_LEFT) { left_pressed = false; } if (g_Event.key.keysym.sym == SDLK_RIGHT) { right_pressed = false; } if (g_Event.key.keysym.sym == SDLK_DOWN) { down_pressed = false; } } } if (down_pressed) { if ( !CheckWallCollisions(g_FocusBlock, DOWN) && !CheckEntityCollisions(g_FocusBlock, DOWN) ) { g_FocusBlock->Move(DOWN); } } if (left_pressed) { if ( !CheckWallCollisions(g_FocusBlock, LEFT) && !CheckEntityCollisions(g_FocusBlock, LEFT) ) { g_FocusBlock->Move(LEFT); } } if (right_pressed) { if ( !CheckWallCollisions(g_FocusBlock, RIGHT) && !CheckEntityCollisions(g_FocusBlock, RIGHT) ) { g_FocusBlock->Move(RIGHT); } } } void HandleExitInput() { if ( SDL_PollEvent(&g_Event) ) { if (g_Event.type == SDL_QUIT) { while (!g_StateStack.empty()) { g_StateStack.pop(); } return; } // Handle keyboard input here // if (g_Event.type == SDL_KEYDOWN) { if (g_Event.key.keysym.sym == SDLK_ESCAPE) { g_StateStack.pop(); return; // this state is done, exit the function } if (g_Event.key.keysym.sym == SDLK_y) { g_StateStack.pop(); return; // game is over, exit the function } if (g_Event.key.keysym.sym == SDLK_n) { StateStruct temp; temp.StatePointer = Menu; g_StateStack.push(temp); return; // this state is done, exit the function } } } } void HandleWinLoseInput() { if ( SDL_PollEvent(&g_Event) ) { // Handle user manually closing game window // if (g_Event.type == SDL_QUIT) { // While state stack isn't empty, pop // while (!g_StateStack.empty()) { g_StateStack.pop(); } return; } // Handle keyboard input here // if (g_Event.type == SDL_KEYDOWN) { if (g_Event.key.keysym.sym == SDLK_ESCAPE) { g_StateStack.pop(); return; } if (g_Event.key.keysym.sym == SDLK_y) { g_StateStack.pop(); return; } if (g_Event.key.keysym.sym == SDLK_n) { g_StateStack.pop(); StateStruct temp; temp.StatePointer = Exit; g_StateStack.push(temp); temp.StatePointer = Menu; g_StateStack.push(temp); return; } } } } bool CheckEntityCollisions(cSquare* square, Direction dir) { int distance = SQUARE_MEDIAN * 2; // Center of the given square // int centerX = square->GetCenterX(); int centerY = square->GetCenterY(); // Determine the location of the square after moving // switch (dir) { case DOWN: { centerY += distance; } break; case LEFT: { centerX -= distance; } break; case RIGHT: { centerX += distance; } break; } for (int i=0; i<g_OldSquares.size(); i++) { if ( ( abs(centerX - g_OldSquares[i]->GetCenterX() ) < distance ) && ( abs(centerY - g_OldSquares[i]->GetCenterY() ) < distance ) ) { return true; } } return false; } bool CheckEntityCollisions(cBlock* block, Direction dir) { cSquare** temp_array = block->GetSquares(); for (int i=0; i<4; i++) { if ( CheckEntityCollisions(temp_array[i], dir) ) return true; } return false; } bool CheckWallCollisions(cSquare* square, Direction dir) { // Get the center of the square // int x = square->GetCenterX(); int y = square->GetCenterY(); switch (dir) { case DOWN: { if ( (y + (SQUARE_MEDIAN*2)) > GAME_AREA_BOTTOM ) { return true; } else { return false; } } break; case LEFT: { if ( (x - (SQUARE_MEDIAN*2)) < GAME_AREA_LEFT ) { return true; } else { return false; } } break; case RIGHT: { if ( (x + (SQUARE_MEDIAN*2)) > GAME_AREA_RIGHT ) { return true; } else { return false; } } break; } return false; } bool CheckWallCollisions(cBlock* block, Direction dir) { cSquare** temp_array = block->GetSquares(); for (int i=0; i<4; i++) { if ( CheckWallCollisions(temp_array[i], dir) ) return true; } return false; } // Check for collisions when a block is rotated // bool CheckRotationCollisions(cBlock* block) { int* temp_array = block->GetRotatedSquares(); int distance = SQUARE_MEDIAN * 2; for (int i=0; i<4; i++) { // Check to see if the block will go out of bounds // if ( (temp_array[i*2] < GAME_AREA_LEFT) || (temp_array[i*2] > GAME_AREA_RIGHT) ) { delete temp_array; return true; } if ( temp_array[i*2+1] > GAME_AREA_BOTTOM ) { delete temp_array; return true; } for (int index=0; index<g_OldSquares.size(); index++) { if ( ( abs(temp_array[i*2] - g_OldSquares[index]->GetCenterX()) < distance ) && ( abs(temp_array[i*2+1] - g_OldSquares[index]->GetCenterY()) < distance ) ) { delete temp_array; return true; } } } delete temp_array; return false; } void HandleBottomCollision() { ChangeFocusBlock(); int num_lines = CheckCompletedLines(); if ( num_lines > 0 ) { g_Score += POINTS_PER_LINE * num_lines; if (g_Score >= g_Level * POINTS_PER_LEVEL) { g_Level++; CheckWin(); // check for a win after increasing the level g_FocusBlockSpeed -= SPEED_CHANGE; // shorten the focus blocks movement interval } } CheckLoss(); } void ChangeFocusBlock() { cSquare** square_array = g_FocusBlock->GetSquares(); // Add focus block squares to g_OldSquares // for (int i=0; i<4; i++) { g_OldSquares.push_back(square_array[i]); } delete g_FocusBlock; // delete the current focus block g_FocusBlock = g_NextBlock; // set the focus block to the next block g_FocusBlock->SetupSquares(BLOCK_START_X, BLOCK_START_Y, g_Bitmap); g_NextBlock = new cBlock(NEXT_BLOCK_CIRCLE_X, NEXT_BLOCK_CIRCLE_Y, g_Bitmap, (BlockType)(rand()%7)); } int CheckCompletedLines() { int squares_per_row[13]; for (int index=0; index<13; index++) squares_per_row[index] = 0; int row_size = SQUARE_MEDIAN * 2; int bottom = GAME_AREA_BOTTOM - SQUARE_MEDIAN; int top = bottom - 12 * row_size; int num_lines = 0; int row; for (int i=0; i<g_OldSquares.size(); i++) { row = (g_OldSquares[i]->GetCenterY() - top) / row_size; squares_per_row[row]++; } // Erase any full lines // for (int line=0; line<13; line++) { // Check for completed lines // if (squares_per_row[line] == SQUARES_PER_ROW) { num_lines++; for (int index=0; index<g_OldSquares.size(); index++) { if ( ( (g_OldSquares[index]->GetCenterY() - top) / row_size ) == line ) { delete g_OldSquares[index]; // delete the square g_OldSquares.erase(g_OldSquares.begin() + index); // remove it from the vector index--; // make sure we don't skip anything } } } } for (int index=0; index<g_OldSquares.size(); index++) { for (int line=0; line<13; line++) { // Determine if this row was filled // if (squares_per_row[line] == SQUARES_PER_ROW) { // If it was, get the location of it within the game area // row = (g_OldSquares[index]->GetCenterY() - top) / row_size; // Now move any squares above that row down one // if ( row < line ) { g_OldSquares[index]->Move(DOWN); } } } } return num_lines; } void CheckWin() { if (g_Level > NUM_LEVELS) { // Clear the old squares vector // for (int i=0; i<g_OldSquares.size(); i++) { delete g_OldSquares[i]; } g_OldSquares.clear(); // Reset score and level // g_Score = 0; g_Level = 1; // Pop all states // while (!g_StateStack.empty()) { g_StateStack.pop(); } // Push the victory state onto the stack // StateStruct win; win.StatePointer = GameWon; g_StateStack.push(win); } } void CheckLoss() { if ( CheckEntityCollisions(g_FocusBlock, DOWN) ) { for (int i=0; i<g_OldSquares.size(); i++) { delete g_OldSquares[i]; } g_OldSquares.clear(); // Reset score and level // g_Score = 0; g_Level = 1; // Pop all states // while (!g_StateStack.empty()) { g_StateStack.pop(); } StateStruct lose; lose.StatePointer = GameLost; g_StateStack.push(lose); } }
even this being a tutorial I worked diligently to get an understanding on how and why the code was there. I got a much better understanding on how things work when it comes to making games and I did type the code in myself so I could see how it was put together and that definitely helped me understand better