Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Two part C++ Tetris game startup Part I - Set up the Bucket Create Tetris bucket

ID: 639897 • Letter: T

Question

Two part C++ Tetris game startup

Part I - Set up the Bucket

Create Tetris bucket

Bucket will be a 2-D array of char of 25 x 12 dimension.

Fill the left border (column 1), right border (column 12), and bottom border (row 25) of the bucket with any char that you like to create the border with. Remember, the array index is '1' lower than the actual # of columns. This can be your "initializeBucket()" function. Fill the other cells with empty string ' '. You know that, to go over a 2-D array you need two nested for loops. Right? You also need conditional statements.

Display the bucket in a game loop. How do you do that? You use two for loops and use a "cout....". You can name the function "displayBucket()".

Remember the top and left most location of the console is (0,0). So, if you want to draw from the top-left most, you call the function this way, "setCursorTo(0, 0);". Then do your 'cout << "etc etc ..."<

void setCursorTo(int x, int y)
{
     HANDLE handle;
     COORD position;
     handle = GetStdHandle(STD_OUTPUT_HANDLE);
     position.X = x;
     position.Y = y;
     SetConsoleCursorPosition(handle, position);
}

Void main(){
     setCursorTo(0, 0);
     cout <<"etc etc ..."< }

Part II - Drop the Shapes into the Bucket

To represent the Tetris shapes, you can create a Class called "TetrisShape". In the class, declare a 2-D array of chars that is 4x4 in size (you could also use 4x2 but that would require different algorithm). Call the array "shapeArray". For convenience, declare it as public (but, it should not be your practice when you work in the software industry). You might need more dimensions for the array if you want to statically assign (hard code) all the shape rotations (3-d) for all the shapes (4-d). In this example, the rotation of the shapes is done by value swapping in the 4x4 array.

Now, populate or initialize the "shapeArray". There are three (3) options for doing this:

Option 1: Add a function in the class (call it "populateShapeArray(int shapeType)"), that will take an integer which will denote the type of shape.

Option 2: Use a non-default constructor. In this case, when you create an object, you will take an integer as the constructor argument, which will denote the type of shape, as shown below.

TetrisShape currentShape = new TetrisShape(shapeType);// shapeType is an int

Option 3: Use a setter "setShape(int shapeType)" function.

Regardless of which option you chose above, you would use a switch statement to assign the 4x4 array values for the specific shape. For example, for 'L', it can be something like the following:

shapeArray[0][0] = ' '; shapeArray[1][0] = 'X'; shapeArray[2][0] = ' '; shapeArray[3][0] = ' ';
shapeArray[0][1] = ' '; shapeArray[1][1] = 'X'; shapeArray[2][1] = ' '; shapeArray[3][1] = ' ';
shapeArray[0][2] = ' '; shapeArray[1][2] = 'X'; shapeArray[2][2] = 'X'; shapeArray[3][2] = ' ';
shapeArray[0][3] = ' '; shapeArray[1][3] = ' '; shapeArray[2][3] = ' '; shapeArray[3][3] = ' ';

bucket[i+shapeTopLeftX][j+shapeTopLeftY] = localTetrisShape.shapeArray[i][j];

You are actually imposing the shape values on to the bucket.

Always keep record of the top left corner location (x,y dimensions) of the shape that is falling. This record will indicate where to draw the shape in the bucket after the shape moves. Initially, the location should be, (6, 0), which is the top middle of the bucket. Store the coordinates in the "TetrisShape" class as shapeTopLeftX and shapeTopLeftY. Note, x changes horizontally, and y changes vertically.

In this step you will generate one shape. To accomplish this, in the main() function, before the while loop (game loop), do the following:

Generate a random number from 0 to 6.

Use one of the options presented in step 2 above to create a TetrisShape object.

Create a global function called "updatebucket(TetrisShape localTetrisShape)" to populate the bucket with values of the "shapeArray". Here, you will use two nested for loops to go over the shapeArray of 4x4. You need to provide the TetrisShape object (created in step '4b' above) to the function as an argument in order to access its shapeArray. Inside the loop, you will do this.

Call the "updatebucket(TetrisShape localTetrisShape)" function from main() using the object created in step 4b.

Display the bucket.

Inside the while loop (game loop), as the shape falls, the value of y will increase. In order to accomplish this you will have "newShapeTopLeftY = shapeTopLeftY + 1;" so that the shape falls one cell below. Notice that you are storing the new y value in another variable because you need both the old and the new values.

Clear (assign spaces to) the current position values of the shape in the bucket using the "old" shapeTopLeftX and shapeTopLeftY. This will ensure that you do not leave any trail of the shape.

Call the "updatebucket(TetrisShape localTetrisShape)" function with the "new" shapeTopLeftX and shapeTopLeftY values. This will ensure the shape will be displayed in the new location (newShapeTopLeftX, newShapeTopLeftY).

Display the bucket. The shape is displayed in the new location of the bucket.

Store the new shapeTopLeftX and shapeTopLeftY values to the old shapeTopLeftX and shapeTopLeftY values to get ready for the next loop.

Sleep for a while to slow down the game.

void setCursorTo(int x, int y)
{
     HANDLE handle;
     COORD position;
     handle = GetStdHandle(STD_OUTPUT_HANDLE);
     position.X = x;
     position.Y = y;
     SetConsoleCursorPosition(handle, position);
}

Void main(){
     setCursorTo(0, 0);
     cout <<"etc etc ..."< }

Explanation / Answer


//main.cpp
//tell compiler to not include many unneeded header files.
#define WIN32_LEAN_AND_MEAN
//need this for windows stuff.
#include <windows.h>
//need this for srand and rand
#include <stdlib.h>
//now let's include our bitmapobject definitions
#include "bitmapobject.h"
  

const int TILESIZE=16;
//now for the map...
const int MAPWIDTH=10;
const int MAPHEIGHT=30;
const int GREY=8;
  
Easy! Now, let's have some (you can use enumerations if you prefer) variables for the future bitmap. We need 9 colors, and 1 Do Not Draw, so 10 in all.
const int TILENODRAW=-1;
const int TILEBLACK=0;
const int TILEGREY=1;
const int TILEBLUE=2;
const int TILERED=3;
const int TILEGREEN=4;
const int TILEYELLOW=5;
const int TILEWHITE=6;
const int TILESTEEL=7;
const int TILEPURPLE=8;
  
Alright, that's done. Let's do some function prototypes. We will need Game Init, Game Loop, Game Done, Draw Tile, Draw Map, New Block, Rotate Block, Collision Test, Move Block, Remove Row, and New Game.
bool GameInit(); // game initialization function
void GameLoop(); //where the game actually takes place
void GameDone(); //clean up!
void DrawTile(int x, int y, int tile); //coordinates & tile type
void DrawMap(); //draw the whole map.. render function, basically
void NewBlock(); //create a new block!
void RotateBlock(); //rotate a block.. if you can!
void Move(int x, int y); //coordinates to move.
int CollisionTest(int nx, int ny); //test collision of blocks
void RemoveRow(int row); //remove a row.. that would be the 'x'.
void NewGame(); //make a new game!
  

struct Piece {
   int size[4][4];
   int x;
   int y;
};


  

//BitMapObject.h
#ifndef BITMAPOBJECT_H
#define BITMAPOBJECT_H
#pragma once
//we need this for windows stuff.
#include <windows.h>
  

class BitMapObject
{
private:
   //memory dc
   HDC hdcMemory;
   //new bitmap!
   HBITMAP hbmNewBitMap;
   //old bitmap.
   HBITMAP hbmOldBitMap;
   //width & height as integers.
   int iWidth;
   int iHeight;
  

public:
   //constructor
   BitMapObject();

   //destructor
   ~BitMapObject();

   //loads bitmap from a file
   void Load(HDC hdcCompatible,LPCTSTR lpszFilename);

   //creates a blank bitmap
   void Create(HDC hdcCompatible, int width, int height);

   //destroys bitmap and dc
   void Destroy();

   //return width
   int GetWidth();

   //return height
   int GetHeight();

   //converts to HDC
   operator HDC();
};

#endif
  

#include "bitmapobject.h"
  

BitMapObject::BitMapObject()
{
   hdcMemory=NULL;
   hbmNewBitMap=NULL;
   hbmOldBitMap=NULL;
   iWidth=0;
   iHeight=0;
}

BitMapObject::~BitMapObject()
{
   //if the hdcMemory hasn't been destroyed, do so
   if(hdcMemory)
       Destroy();
}
  

void BitMapObject::Load(HDC hdcCompatible, LPCTSTR lpszFilename)
{
   //if hdcMemory isn't null, make it so captain!
   if(hdcMemory)
       Destroy();

   //create memory dc.
   hdcMemory=CreateCompatibleDC(hdcCompatible);
   //load the bitmap
   hbmNewBitMap=(HBITMAP)LoadImage(NULL,lpszFilename,IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
   //shove the image into the dc
   hbmOldBitMap=(HBITMAP)SelectObject(hdcMemory,hbmNewBitMap);
   //grab the bitmap's properties
   BITMAP bmp;
   GetObject(hbmNewBitMap,sizeof(BITMAP),(LPVOID)&bmp);
   //grab the width & height
   iWidth=bmp.bmWidth;
   iHeight=bmp.bmHeight;
}
  

void BitMapObject::Create(HDC hdcCompatible, int width, int height)
{
   //if hdcMemory isn't null, blow it up!
   if(hdcMemory)
       Destroy();

   //create the memory dc.
   hdcMemory=CreateCompatibleDC(hdcCompatible);
   //create the bitmap
   hbmNewBitMap=CreateCompatibleBitmap(hdcCompatible, width, height);
   //shove the image into the dc
   hbmOldBitMap=(HBITMAP)SelectObject(hdcMemory, hbmNewBitMap);
   //change the width and height.
   iWidth=width;
   iHeight=height;
}
  

void BitMapObject::Destroy()
{
   //restore old bitmap.
   SelectObject(hdcMemory, hbmOldBitMap);
   //delete new bitmap.
   DeleteObject(hbmNewBitMap);
   //delete device context.
   DeleteDC(hdcMemory);
   //set members to 0/NULL
   hdcMemory=NULL;
   hbmNewBitMap=NULL;
   hbmOldBitMap=NULL;
   iWidth=0;
   iHeight=0;
}
  

BitMapObject::operator HDC()
{
   //return hdcMemory.
   return(hdcMemory);
}

int BitMapObject::GetWidth()
{
   //return width
   return(iWidth);
}

int BitMapObject::GetHeight()
{
   //return height
   return(iHeight);
}
  

LRESULT CALLBACK TheWindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
   //which message did we get?
   switch(uMsg)
   {
   case WM_KEYDOWN:
       {
           //check for escape key
           if(wParam==VK_ESCAPE)
           {
               DestroyWindow(hWndMain);
               return(0);//handled message
           }
           else if(wParam==VK_DOWN) //check for down arrow key
           {
               Move(0,1);
               return(0);//handled message
           }
           else if(wParam==VK_UP) //check for up arrow key
           {
               RotateBlock();
               return(0);//handled message
           }
           else if(wParam==VK_LEFT) //check for left arrow key
           {
               Move(-1,0);
               return(0);//handled message
           }
           else if(wParam==VK_RIGHT) //check for right arrow key
           {
               Move(1,0);
               return(0);//handled message
           }
       }break;
   case WM_DESTROY://the window is being destroyed
       {

           //tell the application we are quitting
           PostQuitMessage(0);

           //handled message, so return 0
           return(0);

       }break;
   case WM_PAINT://the window needs repainting
       {
           //a variable needed for painting information
           PAINTSTRUCT ps;
          
           //start painting
           HDC hdc=BeginPaint(hwnd,&ps);

           //redraw the map
           BitBlt(hdc,0,0,TILESIZE*MAPWIDTH+TILESIZE*GREY,TILESIZE*MAPHEIGHT,bmoMap,0,0,SRCCOPY);

           //end painting
           EndPaint(hwnd,&ps);
                  
           //handled message, so return 0
           return(0);
       }break;
   }

   //pass along any other message to default message handler
   return(DefWindowProc(hwnd,uMsg,wParam,lParam));
}
  
.
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
{
   //assign instance to global variable
   hInstMain=hInstance;

   //create window class
   WNDCLASSEX wcx;

   //set the size of the structure
   wcx.cbSize=sizeof(WNDCLASSEX);

   //class style
   wcx.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;

   //window procedure
   wcx.lpfnWndProc=TheWindowProc;

   //class extra
   wcx.cbClsExtra=0;

   //window extra
   wcx.cbWndExtra=0;

   //application handle
   wcx.hInstance=hInstMain;

   //icon
   wcx.hIcon=LoadIcon(NULL,IDI_APPLICATION);

   //cursor
   wcx.hCursor=LoadCursor(NULL,IDC_ARROW);

   //background color
   wcx.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);

   //menu
   wcx.lpszMenuName=NULL;

   //class name
   wcx.lpszClassName=WINDOWCLASS;

   //small icon
   wcx.hIconSm=NULL;

   //register the window class, return 0 if not successful
   if(!RegisterClassEx(&wcx)) return(0);

   //create main window
   hWndMain=CreateWindowEx(0,WINDOWCLASS,WINDOWTITLE, WS_BORDER | WS_SYSMENU | WS_CAPTION| WS_VISIBLE,0,0,320,240,NULL,NULL,hInstMain,NULL);

   //error check
   if(!hWndMain) return(0);

   //if program initialization failed, then return with 0
   if(!GameInit()) return(0);

   //message structure
   MSG msg;

   //message pump
   for( ; ; )  
   {
       //look for a message
       if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
       {
           //there is a message

           //check that we arent quitting
           if(msg.message==WM_QUIT) break;
          
           //translate message
           TranslateMessage(&msg);

           //dispatch message
           DispatchMessage(&msg);
       }

       //run main game loop
       GameLoop();
      
   }
  
   //clean up program data
   GameDone();

   //return the wparam from the WM_QUIT message
   return(msg.wParam);
}
  

bool GameInit()
{
   //set the client area size
   RECT rcTemp;
   SetRect(&rcTemp,0,0,MAPWIDTH*TILESIZE+TILESIZE*GREY,MAPHEIGHT*TILESIZE);//160x480 client area
   AdjustWindowRect(&rcTemp,WS_BORDER | WS_SYSMENU | WS_CAPTION| WS_VISIBLE,FALSE);//adjust the window size based on desired client area
   SetWindowPos(hWndMain,NULL,0,0,rcTemp.right-rcTemp.left,rcTemp.bottom-rcTemp.top,SWP_NOMOVE);//set the window width and height

   //create map image
   HDC hdc=GetDC(hWndMain);
   bmoMap.Create(hdc,MAPWIDTH*TILESIZE+TILESIZE*GREY,MAPHEIGHT*TILESIZE);
   FillRect(bmoMap,&rcTemp,(HBRUSH)GetStockObject(BLACK_BRUSH));
   ReleaseDC(hWndMain,hdc);

   bmoBlocks.Load(NULL,"blocks.bmp");
   NewGame();

   return(true);//return success
}

void GameDone()
{
   //clean up code goes here
}
  

void GameLoop()
{
   if( (GetTickCount() - start_time) > 1000)
   {
       Move(0,1);
       start_time=GetTickCount();
   }

}
  

void NewGame()
{
   start_time=GetTickCount();
   GAMESTARTED=false;

   //start out the map
   for(int x=0;x< MAPWIDTH;x++)
   {
       for(int y=0;y< MAPHEIGHT+1;y++)
       {
           if(y==MAPHEIGHT) //makes Y-collision easier.
               Map[x][y]=TILEGREY;
           else
               Map[x][y]=TILEBLACK;
       }
   }
   NewBlock();
  
   DrawMap();
}
  

void DrawTile(int x,int y,int tile)//put a tile
{
   //mask first
   BitBlt(bmoMap,x*TILESIZE,y*TILESIZE,TILESIZE,TILESIZE,bmoBlocks,tile*TILESIZE,TILESIZE,SRCAND);
   //then image
   BitBlt(bmoMap,x*TILESIZE,y*TILESIZE,TILESIZE,TILESIZE,bmoBlocks,tile*TILESIZE,0,SRCPAINT);
}
  

void DrawMap()//draw screen
{
   int xmy, ymx;

   //place the toolbar
   for(xmy=MAPWIDTH; xmy< MAPWIDTH+GREY; xmy++)
       for(ymx=0; ymx< MAPHEIGHT; ymx++)
           DrawTile(xmy, ymx, TILEGREY);

   //draw preview block
   for(xmy=0; xmy<4; xmy++)
       for(ymx=0; ymx<4; ymx++)
           if(sPrePiece.size[xmy][ymx] != TILENODRAW)
               DrawTile(sPrePiece.x+xmy, sPrePiece.y+ymx, sPrePiece.size[xmy][ymx]);
  
   //draw the map
   //loop through the positions
   for(xmy=0;xmy< MAPWIDTH;xmy++)
       for(ymx=0;ymx< MAPHEIGHT;ymx++)
               DrawTile(xmy,ymx,Map[xmy][ymx]);

   //draw moving block
   for(xmy=0; xmy<4; xmy++)
       for(ymx=0; ymx<4; ymx++)
           if(sPiece.size[xmy][ymx] != TILENODRAW)
               DrawTile(sPiece.x+xmy, sPiece.y+ymx, sPiece.size[xmy][ymx]);

   //invalidate the window rect
   InvalidateRect(hWndMain,NULL,FALSE);
}
  

void NewBlock()
{
   int newblock;
   int i,j;
   // 0 1 2 3 4 5 6
   // X These
   // X XX X XX XX XX XX are
   // X XX XXX XX XX X X block
   // X X X types

   //begin game! make generate a block and then one in preview.

   srand(GetTickCount());


   //initialize the piece to all blank.
   for(i=0; i<4; i++)
       for(j=0; j<4; j++)
           sPiece.size[ i ][j]=TILENODRAW;

   sPiece.x=MAPWIDTH/2-2;
   sPiece.y=-1;

   //let's see if the game's started yet
   if(GAMESTARTED == false)
   {
       //guess not..
       //Generate a piece right off.
       //From now on, use previous preview block.
       GAMESTARTED=true;

       newblock=rand()%7;

       switch (newblock)
       {
       case 0: //Tower!
           {
               sPiece.size[1][0]=TILERED;
               sPiece.size[1][1]=TILERED;
               sPiece.size[1][2]=TILERED;
               sPiece.size[1][3]=TILERED;
               sPiece.y=0;
           }break;
       case 1: //Box!
           {
               sPiece.size[1][1]=TILEBLUE;
               sPiece.size[1][2]=TILEBLUE;
               sPiece.size[2][1]=TILEBLUE;
               sPiece.size[2][2]=TILEBLUE;
           }break;
       case 2: //Pyramid!
           {
               sPiece.size[1][1]=TILESTEEL;
               sPiece.size[0][2]=TILESTEEL;
               sPiece.size[1][2]=TILESTEEL;
               sPiece.size[2][2]=TILESTEEL;
           }break;
       case 3://Left Leaner
           {
               sPiece.size[0][1]=TILEYELLOW;
               sPiece.size[1][1]=TILEYELLOW;
               sPiece.size[1][2]=TILEYELLOW;
               sPiece.size[2][2]=TILEYELLOW;
           }break;
       case 4://Right Leaner
           {
               sPiece.size[2][1]=TILEGREEN;
               sPiece.size[1][1]=TILEGREEN;
               sPiece.size[1][2]=TILEGREEN;
               sPiece.size[0][2]=TILEGREEN;
           }break;
       case 5://Left Knight
           {
               sPiece.size[1][1]=TILEWHITE;
               sPiece.size[2][1]=TILEWHITE;
               sPiece.size[2][2]=TILEWHITE;
               sPiece.size[2][3]=TILEWHITE;
           }break;
       case 6://Right Knight
           {
               sPiece.size[2][1]=TILEPURPLE;
               sPiece.size[1][1]=TILEPURPLE;
               sPiece.size[1][2]=TILEPURPLE;
               sPiece.size[1][3]=TILEPURPLE;
           }break;
       }
   }
   else
   {
       for(i=0; i<4; i++)
           for(j=0; j<4; j++)
               sPiece.size[ i ][j]=sPrePiece.size[ i ][j];

   }

   newblock=rand()%7;

   for(i=0; i<4; i++)
       for(j=0; j<4; j++)
           sPrePiece.size[ i ][j]=TILENODRAW;

   sPrePiece.x=MAPWIDTH+GREY/4;
   sPrePiece.y=GREY/4;

   switch (newblock)
   {
       case 0: //Tower!
           {
               sPrePiece.size[1][0]=TILERED;
               sPrePiece.size[1][1]=TILERED;
               sPrePiece.size[1][2]=TILERED;
               sPrePiece.size[1][3]=TILERED;
           }break;
       case 1: //Box!
           {
               sPrePiece.size[1][1]=TILEBLUE;
               sPrePiece.size[1][2]=TILEBLUE;
               sPrePiece.size[2][1]=TILEBLUE;
               sPrePiece.size[2][2]=TILEBLUE;
           }break;
       case 2: //Pyramid!
           {
               sPrePiece.size[1][1]=TILESTEEL;
               sPrePiece.size[0][2]=TILESTEEL;
               sPrePiece.size[1][2]=TILESTEEL;
               sPrePiece.size[2][2]=TILESTEEL;
           }break;
       case 3://Left Leaner
           {
               sPrePiece.size[0][1]=TILEYELLOW;
               sPrePiece.size[1][1]=TILEYELLOW;
               sPrePiece.size[1][2]=TILEYELLOW;
               sPrePiece.size[2][2]=TILEYELLOW;
           }break;
       case 4://Right Leaner
           {
               sPrePiece.size[2][1]=TILEGREEN;
               sPrePiece.size[1][1]=TILEGREEN;
               sPrePiece.size[1][2]=TILEGREEN;
               sPrePiece.size[0][2]=TILEGREEN;
           }break;
       case 5://Left Knight
           {
               sPrePiece.size[1][1]=TILEWHITE;
               sPrePiece.size[2][1]=TILEWHITE;
               sPrePiece.size[2][2]=TILEWHITE;
               sPrePiece.size[2][3]=TILEWHITE;
           }break;
       case 6://Right Knight
           {
               sPrePiece.size[2][1]=TILEPURPLE;
               sPrePiece.size[1][1]=TILEPURPLE;
               sPrePiece.size[1][2]=TILEPURPLE;
               sPrePiece.size[1][3]=TILEPURPLE;
           }break;
   }

   DrawMap();
}
  

void RotateBlock()
{
   int i, j, temp[4][4];

   //copy &rotate the piece to the temporary array
   for(i=0; i<4; i++)
       for(j=0; j<4; j++)
           temp[3-j][ i ]=sPiece.size[ i ][j];

   //check collision of the temporary array with map borders
   for(i=0; i<4; i++)
       for(j=0; j<4; j++)
           if(temp[ i ][j] != TILENODRAW)
               if(sPiece.x + i < 0 || sPiece.x + i > MAPWIDTH - 1 ||
                   sPiece.y + j < 0 || sPiece.y + j > MAPHEIGHT - 1)
                   return;

   //check collision of the temporary array with the blocks on the map
   for(int x=0; x< MAPWIDTH; x++)
       for(int y=0; y< MAPHEIGHT; y++)
           if(x >= sPiece.x && x < sPiece.x + 4)
               if(y >= sPiece.y && y < sPiece.y +4)
                   if(Map[x][y] != TILEBLACK)
                       if(temp[x - sPiece.x][y - sPiece.y] != TILENODRAW)
                           return;

   //end collision check

   //successful! copy the rotated temporary array to the original piece
   for(i=0; i<4; i++)
       for(j=0; j<4; j++)
           sPiece.size[ i ][j]=temp[ i ][j];
  
   DrawMap();

   return;
}
  
void Move(int x, int y)
{
   if(CollisionTest(x, y))
   {
       if(y == 1)
       {
           if(sPiece.y<1)
           {
               //you lose! new game.
               NewGame();
           }
           else
           {
               bool killblock=false;
               int i,j;
               //new block time! add this one to the list!
               for(i=0; i<4; i++)
                   for(j=0; j<4; j++)
                       if(sPiece.size[ i ][j] != TILENODRAW)
                           Map[sPiece.x+i][sPiece.y+j] = sPiece.size[ i ][j];

               //check for cleared row!
               for(j=0; j< MAPHEIGHT; j++)
               {
                   bool filled=true;
                   for(i=0; i< MAPWIDTH; i++)
                       if(Map[ i ][j] == TILEBLACK)
                           filled=false;

                   if(filled)
                   {
                       RemoveRow(j);
                       killblock=true;
                   }
               }

               if(killblock)
               {
                   for(i=0; i<4; i++)
                       for(j=0; j<4; j++)
                           sPiece.size[ i ][j]=TILENODRAW;
               }
               NewBlock();
           }
       }

   }
   else
   {
       sPiece.x+=x;
       sPiece.y+=y;
   }

   DrawMap();
}
  

int CollisionTest(int nx, int ny)
{
   int newx=sPiece.x+nx;
   int newy=sPiece.y+ny;

   int i,j,x,y;

   for(i=0; i< 4; i++)
       for(j=0; j< 4; j++)
           if(sPiece.size[ i ][j] != TILENODRAW)
               if(newx + i < 0 || newx + i > MAPWIDTH - 1 ||
                   newy + j < 0 || newy + j > MAPHEIGHT - 1)
                   return 1;

   for(x=0; x< MAPWIDTH; x++)
       for(y=0; y< MAPHEIGHT; y++)
           if(x >= newx && x < newx + 4)
               if(y >= newy && y < newy +4)
                   if(Map[x][y] != TILEBLACK)
                       if(sPiece.size[x - newx][y - newy] != TILENODRAW)
                           return 1;
   return 0;
}
  
void RemoveRow(int row)
{
   int x,y;
   int counter=0;

   for(x=0; x< MAPWIDTH; x++)
       for(y=row; y>0; y--)
           Map[x][y]=Map[x][y-1];

}
  
And that's it! You've got the code, now you just need the graphics. To make the graphics, create a new bitmap of a size TILESIZE*9 width, and TILESIZE*2 height. Now, divide this into 16x16 squares, or whatever TILESIZE you have, and you'll have two rows of 9 columns. Make the bottom row totally black (0 r,0 g,0 b). Make each column of the top row a different color. In order, make the columns Black, Grey, Blue, Red, Green, Yellow, White, Steel, and Purple. Black and Grey should be totally 1 color, while (for a good look!) the other colors should be in this format:
x x x x x x x x x x x x x x x x
x o o o o o o o o o o o o o o m
x o o o o o o o o o o o o o o m
x o o o o o o o o o o o o o o m
x o o o o o o o o o o o o o o m
x o o o o o o o o o o o o o o m
x o o o o o o o o o o o o o o m
x o o o o o o o o o o o o o o m
x o o o o o o o o o o o o o o m
x o o o o o o o o o o o o o o m
x o o o o o o o o o o o o o o m
x o o o o o o o o o o o o o o m
x o o o o o o o o o o o o o o m
x o o o o o o o o o o o o o o m
x o o o o o o o o o o o o o o m
m m m m m m m m m m m m m m m m

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote