Trying to make Tetris

Started by
14 comments, last by vinb 19 years, 10 months ago
Ok. After studying some tutorials as well as all the generous suggestions ( thanks, they are much appreciated ), Here''s what I have so far (that isn''t auto generated by Visual Studio):

struct Tile {	short mX ;	short mY ;	short nColor ;} ;//Block class will be made up of an array of 4 tilesclass Block {	Block();	~Block();public:	Tile* p_tiles[4]; // keep it simple. each block will have 4 tilespublic:	bool move(int nDirection) ; // 1=left, 2=right	bool drop(); // velocity will be controlled by a global variable	bool create() ; // creates a new block	bool destroy() ; // } ;// Linked list to store the blocks that have fallen. Used to detect a complete Rowclass FallenList{public:	Block* p_block ;	Block* p_Next ;public:	bool Insert(Block* pt_block) ; // insert a block into the list	bool Add(Block* pt_block) ; // add a block to end of the list	bool RemoveRow(int t_y) ; // gets rid of full rows	bool ShiftRowsDown(int t_y); // move all rows above m_y down by one	void Clear(); // clear out entire list	bool Occupied(int t_x, int t_y) ;// determine if block at (t_x, t_y) is occupied	FallenList() ;	~FallenList() ;} ; 


By the way, is it cheating to use someone elses directx library? I mean, honestly, at this point the ones that I''ve seen I understand what they do and I know where to look to get what I need. But it would seem like calling wheel.reinvent to write them from scratch. Oh well. I would appreciate anyone''s progress report for what I have so far.
Advertisement
Ok, let me try those source tags one more time (sorry!)
struct Tile {	short mX ;	short mY ;	short nColor ;} ;//Block class will be made up of an array of 4 tilesclass Block {	Block();	~Block();public:	Tile* p_tiles[4]; // keep it simple. each block will have 4 tilespublic:	bool move(int nDirection) ; // 1=left, 2=right	bool drop(); // velocity will be controlled by a global variable	bool create() ; // creates a new block	bool destroy() ; // } ;// Linked list to store the blocks that have fallen. Used to detect a complete Rowclass FallenList{public:	Block* p_block ;	Block* p_Next ;public:	bool Insert(Block* pt_block) ; // insert a block into the list	bool Add(Block* pt_block) ; // add a block to end of the list	bool RemoveRow(int t_y) ; // gets rid of full rows	bool ShiftRowsDown(int t_y); // move all rows above m_y down by one	void Clear(); // clear out entire list	bool Occupied(int t_x, int t_y) ;// determine if block at (t_x, t_y) is occupied	FallenList() ;	~FallenList() ;} ;
Vinb, I wonder if any body had mistaken you for me. I have posted some many threads about this very subject I wonder if any one remembers me when I first came to GameDev asking very similar questions. The only difference was I didn’t know a thing about programming when I first came to GameDev. I do now, but that hasn’t changed much.

Here are a few things to help you out.
1. Don’t worry about the graphics first.
2. Worry about the logic first.
3. Don’t go ever board on super-graphics (It’s just a Tetris game)
4. Good luck.

// EDIT: How could forget a name like Sakky?


[edited by - sakky on June 4, 2004 12:58:00 PM]
Take back the internet with the most awsome browser around, FireFox
Roughly, that looks like a pretty good start to me.

I''m not quite clear on your data structure for the blocks. I assume you want a list of them, but I don''t see how you can link them together given the code you have. Perhaps you could have the p_Next be in the block class instead of the FallenList class?

Another probably better option unless you want the practice of coding the list yourself would be to use one of the std:: container classes to hold the blocks, they are usually easier to use than coding it yourself.

And, no I don''t see any problem with using somebody else''s DirectX library, if you are willing to learn it. Eventually learning more about the APIs directly would be beneficial, but one step at a time.
What I did to solve the dropping figure problem was to use a time stamp. Then if the time stamp – the level x the decent rate, it was time to drop the figure again. Here is what I used

double fLastTime = 0.0; // global// Do timed decent logic//double fTime  = GetTockCount( ) * 0.001;int nLevel = 0;if ( fTime – fLastTime > ( double )( 1.0 - ( nLevel * 0.1 ) ) ){        fLastTime = fTime;	// Drop the figure}else{	// Drink a cup of coffee}


In this logic, the levels are 0 based i.e. 0 – 9. So 0(being the first level) multiplied by 0.1 = 0. So a full second passes before the figure drops.

This way, you don’t have to have any pesky global variables. All you need is the level variable that can be kept local or private.

I also used

nLevel = ( nLines / 15 );

to get the current level I was on. So I really didn’t even need a level variable, just a score variable. It actually works quite well. Try it out if you would like


[edited by - sakky on June 5, 2004 1:46:46 AM]
Take back the internet with the most awsome browser around, FireFox
This is what I had for my Tetris clode I was working on.


#include <WINDOWS.H>#include <STDLIB.H>#include <STDIO.H>struct BOARD{	CHAR umBoard[ 14 ][ 21 ];	CHAR uLines;};struct BLOCK{	CHAR umBlock[ 4 ][ 4 ];	CHAR uX;	CHAR uY;};const CHAR  g_mmBlockI[ 4 ][ 4 ] = { { 0, 1, 0, 0 }, { 0, 1, 0, 0 }, { 0, 1, 0, 0 }, { 0, 1, 0, 0 }, };const CHAR  g_mmBlockJ[ 4 ][ 4 ] = { { 0, 1, 0, 0 }, { 0, 1, 0, 0 }, { 1, 1, 0, 0 }, { 0, 0, 0, 0 }, };const CHAR  g_mmBlockL[ 4 ][ 4 ] = { { 1, 0, 0, 0 }, { 1, 0, 0, 0 }, { 1, 1, 0, 0 }, { 0, 0, 0, 0 }, };const CHAR  g_mmBlockO[ 4 ][ 4 ] = { { 1, 1, 0, 0 }, { 1, 1, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, };const CHAR  g_mmBlockS[ 4 ][ 4 ] = { { 0, 1, 1, 0 }, { 1, 1, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, };const CHAR  g_mmBlockT[ 4 ][ 4 ] = { { 1, 1, 1, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, };const CHAR  g_mmBlockZ[ 4 ][ 4 ] = { { 1, 1, 0, 0 }, { 0, 1, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, };double		g_fLastTime			 = 0.0;HBRUSH		g_hbrBlock			 = CreateSolidBrush( RGB( 100, 100, 120 ) );HBRUSH		g_hbrSpace			 = CreateSolidBrush( RGB( 0, 0, 0 ) );BOARD		g_Board				 = { 0 };BLOCK		g_Block				 = { 0 };BOOL		g_bDoUpdate			 = FALSE;//-----------------------------------------------------------------------------//	Reset the game board//VOID ResetGameBoard( ){		for ( int i = 0; i < 21; ++i )		for ( int j = 0; j < 14; ++j )			if ( i == 20 || j == 0 || j == 13 )				g_Board.umBoard[ j ][ i ] = 1;			else				g_Board.umBoard[ j ][ i ] = 0;		g_Board.uLines = 0;}//-----------------------------------------------------------------------------//	Generate a new random figure//VOID GenerateRandomBlock( ){	CHAR uBlock = ( rand( ) % 7 ) + 1;		switch ( uBlock )	{	case 1: memcpy( g_Block.umBlock, g_mmBlockI, 16 ); break;	case 2: memcpy( g_Block.umBlock, g_mmBlockJ, 16 ); break;	case 3: memcpy( g_Block.umBlock, g_mmBlockL, 16 ); break;	case 4: memcpy( g_Block.umBlock, g_mmBlockO, 16 ); break;	case 5: memcpy( g_Block.umBlock, g_mmBlockS, 16 ); break;	case 6: memcpy( g_Block.umBlock, g_mmBlockT, 16 ); break;	case 7: memcpy( g_Block.umBlock, g_mmBlockZ, 16 ); break;	}		g_Block.uX = 6;	g_Block.uY = 0;}//-----------------------------------------------------------------------------//	Check for a collision on the board//BOOL CheckCollision	(	CHAR umBlock[ 4 ][ 4 ]	){	for ( int i = 0; i < 4; ++i )		for ( int j = 0; j < 4; ++j )			if ( umBlock[ j ][ i ] == 0 )				break;			else			if ( g_Board.umBoard[ j + g_Block.uX ][ i + g_Block.uY ] + umBlock[ j ][ i ] != umBlock[ j ][ i ] )				return TRUE;	return FALSE;}//-----------------------------------------------------------------------------//	Move a block//BOOL MoveBlock( int nDX, int nDY ){	int nTempX, nTempY;	nTempX = g_Block.uX;	nTempY = g_Block.uY;	g_Block.uX += nDX;	g_Block.uY += nDY;		if ( TRUE == CheckCollision( g_Block.umBlock ) )	{		g_Block.uX = nTempX;		g_Block.uY = nTempY;		return TRUE;	}		return FALSE;}//-----------------------------------------------------------------------------//	Rotate a block 90 degrees//VOID RotateBlock( ){	CHAR i, j, umFig[ 4 ][ 4 ];		for ( i = 0; i < 4; ++i )		for ( j = 0; j < 4; ++j )			umFig[ j ][ i ] = g_Block.umBlock[ 4 - i ][ j ];	if ( TRUE == CheckCollision( umFig ) )		return;	for ( i = 0; i < 4; ++i )		for ( j = 0; j < 4; ++j )			umFig[ j ][ i ] = g_Block.umBlock[ j ][ i ];}//-----------------------------------------------------------------------------//	Insert a block//VOID InsertBlock( ){	for ( int i = 0; i < 4; ++i )		for ( int j = 0; j < 4; ++j )			if ( g_Block.umBlock[ j ][ i ] != 0 )				g_Board.umBoard[ g_Block.uX + j ][  g_Block.uY + i ] = g_Block.umBlock[ j ][ i ];}//-----------------------------------------------------------------------------//	Remove completed lines//VOID RemoveLine( UINT uIndex ){	for ( int i = uIndex; i > 0; --i )		for ( int j = 1; j < 13; ++j )			g_Board.umBoard[ j ][ i ] = g_Board.umBoard[ j ][ i - 1 ];}//-----------------------------------------------------------------------------//	Search for completed lines//VOID SearchLines( ){	CHAR uNumBlocks = 0;	for ( int i = 0; i < 21; ++i )		for ( int j = 1; j < 13; ++j )			if ( g_Board.umBoard[ j ][ i ] == 0 )			{				uNumBlocks = 0;				break;			}			else			{				++uNumBlocks;				if ( uNumBlocks >= 12 )				{					RemoveLine( i );					++g_Board.uLines;					--i;				}			}}//-----------------------------------------------------------------------------//	Paint the scene//VOID PaintScene( HWND hWnd ){	CHAR		cvBuffer[ 80 ];	RECT		rcBlock;	HDC			hDC;	int			i, j;		hDC = GetDC( hWnd );		for ( i = 0; i < 20; ++i )		for ( j = 1; j < 13; ++j )		{			rcBlock.top		= ( i * 16 ) + 4;			rcBlock.left	= ( j * 16 ) + 4;			rcBlock.bottom	= rcBlock.top  + 16;			rcBlock.right	= rcBlock.left + 16;					if ( g_Board.umBoard[ j ][ i ] == 0 )				FillRect( hDC, &rcBlock, g_hbrSpace );			else				FillRect( hDC, &rcBlock, g_hbrBlock );		}		for ( i = 0; i < 4; ++i )		for ( j = 0; j < 4; ++j )			if ( g_Block.umBlock[ j ][ i ] == 0 )				break;			else			{				rcBlock.top		= ( ( g_Block.uY + i ) * 16 ) + 4;				rcBlock.left	= ( ( g_Block.uX + j ) * 16 ) + 4;				rcBlock.bottom	= rcBlock.top  + 16;				rcBlock.right   = rcBlock.left + 16;				if ( g_Block.umBlock[ j ][ i ] != 0 )					FillRect( hDC, &rcBlock, g_hbrBlock );			}	SetBkColor( hDC, RGB( 100, 120, 100 ) );	SetTextColor( hDC, RGB( 255, 240, 50 ) );	sprintf( cvBuffer, "Level: %i", ( g_Board.uLines / 15 ) );	TextOut( hDC, 210, 100, cvBuffer, ( int )strlen( cvBuffer ) );	sprintf( cvBuffer, "Lines: %i", g_Board.uLines );	TextOut( hDC, 210, 135, cvBuffer, ( int )strlen( cvBuffer ) );	ReleaseDC( hWnd, hDC );}//-----------------------------------------------------------------------------//	Process Win32 application messages//LRESULT CALLBACK WindowProc	( 	HWND		hWnd, 	UINT		uMessage, 	WPARAM		wParam, 	LPARAM		lParam 	){	switch ( uMessage )	{	case WM_LBUTTONDOWN:		 SendMessage( hWnd, WM_NCLBUTTONDOWN, HTCAPTION, lParam );		 return 0L;	case WM_KEYDOWN:		 switch ( LOWORD( wParam ) )		 {		 case VK_ESCAPE:			  PostQuitMessage( 0 );			  break;		 case VK_LEFT:			  MoveBlock( -1, 0 );			  g_bDoUpdate = TRUE;			  break;		 case VK_RIGHT:			  MoveBlock( 1, 0 );			  g_bDoUpdate = TRUE;			  break;		 case VK_DOWN:			  MoveBlock( 0, 1 );			  g_bDoUpdate = TRUE;			  break;		  		 case VK_SPACE:			  RotateBlock( );			  g_bDoUpdate = TRUE;			  break;		 }		 return 0L;	case WM_DESTROY:		 PostQuitMessage( 0 );		 return 0L;	}	return DefWindowProc( hWnd, uMessage, wParam, lParam );}//-----------------------------------------------------------------------------//	Application entry point//int WINAPI WinMain	( 	HINSTANCE	hInstance,	HINSTANCE	hPrevInstance,	LPSTR		lpCmdLine,	int			nShowCmd	){	WNDCLASS			sWC;	HWND				hWnd;	MSG					sMsg;	memset( &sWC, 0, sizeof( WNDCLASS ) );	sWC.hbrBackground	= CreateSolidBrush( RGB( 100, 120, 100 ) );	sWC.hCursor			= LoadCursor( NULL, IDC_ARROW );	sWC.hIcon			= LoadIcon( NULL, IDI_WINLOGO );	sWC.hInstance		= hInstance;	sWC.lpfnWndProc		= WindowProc;	sWC.lpszClassName	= "DEMO";	RegisterClass( &sWC );		hWnd = CreateWindow( "DEMO", "Demo", WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | 	WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 270, 400, NULL, NULL, hInstance, NULL );	ResetGameBoard( );	GenerateRandomBlock( );	PeekMessage( &sMsg, NULL, 0U, 0U, PM_NOREMOVE );	while ( WM_QUIT != sMsg.message )		if ( PeekMessage( &sMsg, NULL, 0U, 0U, PM_REMOVE ) )		{			TranslateMessage( &sMsg );			DispatchMessage( &sMsg );		}		else		{			double fTime = GetTickCount( ) * 0.001;						if ( fTime - g_fLastTime > ( 1.0 - ( ( g_Board.uLines / 15 ) * 0.1 ) ) )			{				g_fLastTime = fTime;							if ( MoveBlock( 0, 1 ) )				{					InsertBlock( );					SearchLines( );					GenerateRandomBlock( );				}								g_bDoUpdate = TRUE;			}						if ( TRUE == g_bDoUpdate )			{				PaintScene( hWnd );				g_bDoUpdate = FALSE;			}		}	return ( int )sMsg.wParam;}
Take back the internet with the most awsome browser around, FireFox

This topic is closed to new replies.

Advertisement