Tetris for beginners help!

Started by
18 comments, last by Codarki 15 years, 1 month ago
I have recently looked into the article about tetris for beginners, http://www.gamedev.net/community/forums/topic.asp?topic_id=192483&PageSize=25&WhichPage=1 and I use Dev-C++, and I have included the "blocks.bmp" file in the project along with the others... and it compiles and runs fine, except its just a black screen...help!
Advertisement
Help please!?
can you post the code or give a link to what you have so we can test it out and see what the issue is
//FALLING BLOCK GAME!
//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"

//let's give our window a name
#define WINDOWCLASS "FallingBlockGame"
//let's give our window a title...er caption.
#define WINDOWTITLE "A Falling Block Game!"

//since we're using square blocks, let's only use a single size.
const int TILESIZE=16;
//now for the map...
const int MAPWIDTH=10;
const int MAPHEIGHT=30;
const int GREY=8;

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;

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!

HINSTANCE hInstMain=NULL; //main app handle
HWND hWndMain=NULL; //main window handle

int Map[MAPWIDTH][MAPHEIGHT+1]; //the game map!

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

Piece sPrePiece; //preview piece.
Piece sPiece; //the 's' prefixes indicate this is a 'structure'

DWORD start_time; //used in timing
bool GAMESTARTED=false; //used by NewBlock()

//map for the program
BitMapObject bmoMap;
//block images
BitMapObject bmoBlocks;

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[j]=TILENODRAW;<br><br> sPiece.x=MAPWIDTH/2-2;<br> sPiece.y=-1;<br><br> //let's see if the game's started yet<br> if(GAMESTARTED == false)<br> {<br> //guess not.. <br> //Generate a piece right off.<br> //From now &#111;n, use previous preview block.<br> GAMESTARTED=true;<br><br> newblock=rand()%7;<br><br> switch (newblock)<br> {<br> case 0: //Tower!<br> {<br> sPiece.size[1][0]=TILERED;<br> sPiece.size[1][1]=TILERED;<br> sPiece.size[1][2]=TILERED;<br> sPiece.size[1][3]=TILERED;<br> sPiece.y=0;<br> }break;<br> case 1: //Box!<br> {<br> sPiece.size[1][1]=TILEBLUE;<br> sPiece.size[1][2]=TILEBLUE;<br> sPiece.size[2][1]=TILEBLUE;<br> sPiece.size[2][2]=TILEBLUE;<br> }break;<br> case 2: //Pyramid!<br> {<br> sPiece.size[1][1]=TILESTEEL;<br> sPiece.size[0][2]=TILESTEEL;<br> sPiece.size[1][2]=TILESTEEL;<br> sPiece.size[2][2]=TILESTEEL;<br> }break;<br> case 3://Left Leaner<br> {<br> sPiece.size[0][1]=TILEYELLOW;<br> sPiece.size[1][1]=TILEYELLOW;<br> sPiece.size[1][2]=TILEYELLOW;<br> sPiece.size[2][2]=TILEYELLOW;<br> }break;<br> case 4://Right Leaner<br> {<br> sPiece.size[2][1]=TILEGREEN;<br> sPiece.size[1][1]=TILEGREEN;<br> sPiece.size[1][2]=TILEGREEN;<br> sPiece.size[0][2]=TILEGREEN;<br> }break;<br> case 5://Left Knight<br> {<br> sPiece.size[1][1]=TILEWHITE;<br> sPiece.size[2][1]=TILEWHITE;<br> sPiece.size[2][2]=TILEWHITE;<br> sPiece.size[2][3]=TILEWHITE;<br> }break;<br> case 6://Right Knight<br> {<br> sPiece.size[2][1]=TILEPURPLE;<br> sPiece.size[1][1]=TILEPURPLE;<br> sPiece.size[1][2]=TILEPURPLE;<br> sPiece.size[1][3]=TILEPURPLE;<br> }break;<br> }<br> }<br> else<br> {<br> for(i=0; i&lt;4; i++)<br> for(j=0; j&lt;4; j++)<br> sPiece.size[j]=sPrePiece.size[j];<br><br> }<br><br> newblock=rand()%7;<br><br> for(i=0; i&lt;4; i++)<br> for(j=0; j&lt;4; j++)<br> sPrePiece.size[j]=TILENODRAW;<br><br> sPrePiece.x=MAPWIDTH+GREY/4;<br> sPrePiece.y=GREY/4;<br><br> switch (newblock)<br> {<br> case 0: //Tower!<br> {<br> sPrePiece.size[1][0]=TILERED;<br> sPrePiece.size[1][1]=TILERED;<br> sPrePiece.size[1][2]=TILERED;<br> sPrePiece.size[1][3]=TILERED;<br> }break;<br> case 1: //Box!<br> {<br> sPrePiece.size[1][1]=TILEBLUE;<br> sPrePiece.size[1][2]=TILEBLUE;<br> sPrePiece.size[2][1]=TILEBLUE;<br> sPrePiece.size[2][2]=TILEBLUE;<br> }break;<br> case 2: //Pyramid!<br> {<br> sPrePiece.size[1][1]=TILESTEEL;<br> sPrePiece.size[0][2]=TILESTEEL;<br> sPrePiece.size[1][2]=TILESTEEL;<br> sPrePiece.size[2][2]=TILESTEEL;<br> }break;<br> case 3://Left Leaner<br> {<br> sPrePiece.size[0][1]=TILEYELLOW;<br> sPrePiece.size[1][1]=TILEYELLOW;<br> sPrePiece.size[1][2]=TILEYELLOW;<br> sPrePiece.size[2][2]=TILEYELLOW;<br> }break;<br> case 4://Right Leaner<br> {<br> sPrePiece.size[2][1]=TILEGREEN;<br> sPrePiece.size[1][1]=TILEGREEN;<br> sPrePiece.size[1][2]=TILEGREEN;<br> sPrePiece.size[0][2]=TILEGREEN;<br> }break;<br> case 5://Left Knight<br> {<br> sPrePiece.size[1][1]=TILEWHITE;<br> sPrePiece.size[2][1]=TILEWHITE;<br> sPrePiece.size[2][2]=TILEWHITE;<br> sPrePiece.size[2][3]=TILEWHITE;<br> }break;<br> case 6://Right Knight<br> {<br> sPrePiece.size[2][1]=TILEPURPLE;<br> sPrePiece.size[1][1]=TILEPURPLE;<br> sPrePiece.size[1][2]=TILEPURPLE;<br> sPrePiece.size[1][3]=TILEPURPLE;<br> }break;<br> }<br><br> DrawMap();<br>}<br> <br>void RotateBlock()<br>{<br> int i, j, temp[4][4];<br><br> //copy &rotate the piece to the temporary array<br> for(i=0; i&lt;4; i++)<br> for(j=0; j&lt;4; j++)<br> temp[3-j]=sPiece.size[j];<br><br> //check collision of the temporary array with map borders<br> for(i=0; i&lt;4; i++)<br> for(j=0; j&lt;4; j++)<br> if(temp[j] != TILENODRAW)<br> if(sPiece.x + i &lt; 0 || sPiece.x + i &gt; MAPWIDTH - 1 ||<br> sPiece.y + j &lt; 0 || sPiece.y + j &gt; MAPHEIGHT - 1)<br> return;<br><br> //check collision of the temporary array with the blocks &#111;n the map<br> for(int x=0; x&lt; MAPWIDTH; x++)<br> for(int y=0; y&lt; MAPHEIGHT; y++)<br> if(x &gt;= sPiece.x && x &lt; sPiece.x + 4)<br> if(y &gt;= sPiece.y && y &lt; sPiece.y +4)<br> if(Map[x][y] != TILEBLACK)<br> if(temp[x - sPiece.x][y - sPiece.y] != TILENODRAW)<br> return;<br><br> //end collision check<br><br> //successful! copy the rotated temporary array to the original piece<br> for(i=0; i&lt;4; i++)<br> for(j=0; j&lt;4; j++)<br> sPiece.size[j]=temp[j];<br> <br> DrawMap();<br><br> return;<br>}<br><br>void Move(int x, int y)<br>{<br> if(CollisionTest(x, y))<br> {<br> if(y == 1)<br> {<br> if(sPiece.y&lt;1)<br> {<br> //you lose! new game.<br> NewGame();<br> }<br> else<br> {<br> bool killblock=false;<br> int i,j;<br> //new block time! add this &#111;ne to the list!<br> for(i=0; i&lt;4; i++)<br> for(j=0; j&lt;4; j++)<br> if(sPiece.size[j] != TILENODRAW)<br> Map[sPiece.x+i][sPiece.y+j] = sPiece.size[j];<br><br> //check for cleared row!<br> for(j=0; j&lt; MAPHEIGHT; j++)<br> {<br> bool filled=true;<br> for(i=0; i&lt; MAPWIDTH; i++)<br> if(Map[j] == TILEBLACK)<br> filled=false;<br><br> if(filled)<br> {<br> RemoveRow(j);<br> killblock=true;<br> }<br> }<br><br> if(killblock)<br> {<br> for(i=0; i&lt;4; i++)<br> for(j=0; j&lt;4; j++)<br> sPiece.size[j]=TILENODRAW;<br> }<br> NewBlock();<br> }<br> }<br><br> }<br> else<br> {<br> sPiece.x+=x;<br> sPiece.y+=y;<br> }<br><br> DrawMap();<br>}<br><br>int CollisionTest(int nx, int ny)<br>{<br> int newx=sPiece.x+nx;<br> int newy=sPiece.y+ny;<br><br> int i,j,x,y;<br><br> for(i=0; i&lt; 4; i++)<br> for(j=0; j&lt; 4; j++)<br> if(sPiece.size[j] != TILENODRAW)<br> if(newx + i &lt; 0 || newx + i &gt; MAPWIDTH - 1 ||<br> newy + j &lt; 0 || newy + j &gt; MAPHEIGHT - 1)<br> return 1;<br><br> for(x=0; x&lt; MAPWIDTH; x++)<br> for(y=0; y&lt; MAPHEIGHT; y++)<br> if(x &gt;= newx && x &lt; newx + 4)<br> if(y &gt;= newy && y &lt; newy +4)<br> if(Map[x][y] != TILEBLACK)<br> if(sPiece.size[x - newx][y - newy] != TILENODRAW)<br> return 1;<br> return 0;<br>}<br> <br><br>void RemoveRow(int row)<br>{<br> int x,y;<br> int counter=0;<br><br> for(x=0; x&lt; MAPWIDTH; x++)<br> for(y=row; y&gt;0; y–)<br> Map[x][y]=Map[x][y-1];<br><br>}<br> <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>//BitMapObject.h<br>#ifndef BITMAPOBJECT_H<br>#define BITMAPOBJECT_H<br>#pragma &#111;nce<br>//we need this for windows stuff.<br>#include &lt;windows.h&gt;<br> <br>class BitMapObject<br>{<br>private:<br> //memory dc<br> HDC hdcMemory;<br> //new bitmap!<br> HBITMAP hbmNewBitMap;<br> //old bitmap.<br> HBITMAP hbmOldBitMap;<br> //width & height as integers.<br> int iWidth;<br> int iHeight;<br> <br> public:<br> //constructor<br> BitMapObject();<br><br> //destructor<br> ~BitMapObject();<br><br> //loads bitmap from a file<br> void Load(HDC hdcCompatible,LPCTSTR lpszFilename);<br><br> //creates a blank bitmap<br> void Create(HDC hdcCompatible, int width, int height);<br><br> //destroys bitmap and dc<br> void Destroy();<br><br> //return width<br> int GetWidth();<br><br> //return height<br> int GetHeight();<br><br> //converts to HDC<br> operator HDC();<br>};<br><br>#endif<br> <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>//BitMapObject.cpp<br>#include "bitmapobject.h"<br> <br>BitMapObject::BitMapObject()<br>{<br> hdcMemory=NULL;<br> hbmNewBitMap=NULL;<br> hbmOldBitMap=NULL;<br> iWidth=0;<br> iHeight=0;<br>}<br><br>BitMapObject::~BitMapObject()<br>{<br> //if the hdcMemory hasn't been destroyed, do so<br> if(hdcMemory)<br> Destroy();<br>}<br> <br>void BitMapObject::Load(HDC hdcCompatible, LPCTSTR lpszFilename)<br>{<br> //if hdcMemory isn't null, make it so captain!<br> if(hdcMemory)<br> Destroy();<br><br> //create memory dc.<br> hdcMemory=CreateCompatibleDC(hdcCompatible);<br> //load the bitmap<br> hbmNewBitMap=(HBITMAP)LoadImage(NULL,lpszFilename,IMAGE_BITMAP,0,0,LR_LOADFROMFILE);<br> //shove the image into the dc<br> hbmOldBitMap=(HBITMAP)SelectObject(hdcMemory,hbmNewBitMap);<br> //grab the bitmap's properties<br> BITMAP bmp;<br> GetObject(hbmNewBitMap,sizeof(BITMAP),(LPVOID)&bmp);<br> //grab the width & height<br> iWidth=bmp.bmWidth;<br> iHeight=bmp.bmHeight;<br>}<br><br>void BitMapObject::Create(HDC hdcCompatible, int width, int height)<br>{<br> //if hdcMemory isn't null, blow it up!<br> if(hdcMemory)<br> Destroy();<br><br> //create the memory dc.<br> hdcMemory=CreateCompatibleDC(hdcCompatible);<br> //create the bitmap<br> hbmNewBitMap=CreateCompatibleBitmap(hdcCompatible, width, height);<br> //shove the image into the dc<br> hbmOldBitMap=(HBITMAP)SelectObject(hdcMemory, hbmNewBitMap);<br> //change the width and height.<br> iWidth=width;<br> iHeight=height;<br>}<br><br>void BitMapObject::Destroy()<br>{<br> //restore old bitmap.<br> SelectObject(hdcMemory, hbmOldBitMap);<br> //delete new bitmap.<br> DeleteObject(hbmNewBitMap);<br> //delete device context.<br> DeleteDC(hdcMemory);<br> //set members to 0/NULL<br> hdcMemory=NULL;<br> hbmNewBitMap=NULL;<br> hbmOldBitMap=NULL;<br> iWidth=0;<br> iHeight=0;<br>}<br> <br>BitMapObject::operator HDC()<br>{<br> //return hdcMemory.<br> return(hdcMemory);<br>}<br><br>int BitMapObject::GetWidth()<br>{<br> //return width<br> return(iWidth);<br>}<br><br>int BitMapObject::GetHeight()<br>{<br> //return height<br> return(iHeight);<br>}<br><br><br><br><br><br>blocks.bmp is also saved in the same folder.<br><br>all i get is black screen, with a title of falling blocks…<br><br><br><br>
You need to put the bitmap in the same folder were the exe is. Usealy in the default folder or something like that.
blocks.bmp is also saved in the same folder
How many lines is that program? It seems huge for tetris!
Poor little kittens, they've lost their mittens!And now you all must die!Mew mew mew, mew mew mew mew!And now you all must die!-Pete Abrams
It's around 750. O_O
O.O

Shortest tetris code ever (by line count, unverified claim I'm making right now):
http://www.matthewleverton.com/misc/20lines.html


I don't really know how long a normal (as in, actually readable) tetris game's code should be, but 750 lines seems a bit long.
Poor little kittens, they've lost their mittens!And now you all must die!Mew mew mew, mew mew mew mew!And now you all must die!-Pete Abrams
im sorry, but I really have no idea what that 20 lines of code means...it compiles...

but thats about all I can get from it.

could I have some help on something more on my level?

i got this program from this site...

This topic is closed to new replies.

Advertisement