www.pudn.com > Tetris.rar > CGameTetris.cpp


// 2005-8-31 修正了按键响应慢的错误 
#include  
#include  
#include  
 
#include "CGameTetris.h" 
#include  
 
 
// construct and destruct 
 
// NewL() 
CGameTetris* CGameTetris::NewL() 
{ 
	CGameTetris* self = new (ELeave) CGameTetris; 
	CleanupStack::PushL(self); 
 
	self->ConstructL(); 
 
	CleanupStack::Pop(self); 
 
	return self; 
} 
 
 
// CGameTetris() 
CGameTetris::CGameTetris() : iGrid() 
{} 
 
 
// ~ 
CGameTetris::~CGameTetris() 
{ 
	iBmpBlock.DeleteAll(); 
	delete iBmpBackground; 
} 
 
void CGameTetris::ConstructL() 
{ 
	// load game resource 
	LoadResL(); 
 
	// Make the seed 
	TTime time; 
	time.HomeTime(); 
	iSeed = time.Int64(); 
} 
 
//////////////////////////////////////////////////////////////////////////////// 
 
// Method 
 
// handel all key relatively 
TBool CGameTetris::Command(TInt aCommand) 
{ 
	switch(aCommand) 
	{ 
		case EKeyRightArrow :			// right 
		case '6' : 
		{ 
			MoveTo(iBlockPos + TPoint(1, 0));	 
		}return 1; 
 
		case EKeyLeftArrow :			// left 
		case '4' : 
		{ 
			MoveTo(iBlockPos + TPoint(-1, 0)); 
		}return 1; 
 
		case EKeyUpArrow :				// up 
		case '2' : 
		case '5' : 
		case 63557 : 
		{ 
			Rotate(); 
		}return 1; 
 
		case EKeyDownArrow :			// down 
		case '8' : 
		{ 
			while(MoveTo(iBlockPos + TPoint(0, 1))); 
		}return 1; 
 
		default:return 0; 
	} 
} 
 
// move down the block automatic 
TInt8 CGameTetris::Run() 
{ 
	TInt8 flag = 0;				// default not update view 
	 
	if(!iStateRunning)			// game is not running 
	{ 
		iStateRunning = 1; 
		StartNewGame(); 
	} 
	else 
	{ 
		if(!iDelay) 
		{ 
			if(!MoveTo(iBlockPos + TPoint(0, 1)))	// if can't move down the block 
			{ 
				if(!FixBlock())		// check if the block is out of bound 
				{ 
					iStateRunning = 0; 
					return 1;		// Game over 
				} 
				TInt eliminate = CheckRows(); 
				 
				if(eliminate) 
				{ 
					Calculate(eliminate); 
					if(eliminate == 4) 
						iStateWellDone = 1;	// well done 
					iStateClearRow = 1;	//  explode sound 
				} 
 
				NewBlock();		// create a new one 
			} 
			flag = 2;			// update view 
		} 
	 
		iDelay = iDelay ? --iDelay : 10-iLevel; 
	} 
 
	return flag; 
} 
 
// Draw() 
void CGameTetris::Draw(CFbsBitGc* aBackBufferGc) 
{ 
	TInt xPos, yPos; 
	TUint8 i, j; 
	// draw background 
	aBackBufferGc->BitBlt(TPoint(0, 0), iBmpBackground); 
 
	// draw blocks 
	yPos = 0; 
	TFixedArray arr; 
	for(i = 0; i < KGridY; i++) 
	{ 
		xPos = 9; 
		GetRowContent(i, arr); 
		for(j = 0; j < KGridX; j++) 
		{ 
			TUint8 blockType = arr[j]; 
			if(blockType) 
			{ 
				TPoint pos = TPoint(xPos, yPos); 
		 		aBackBufferGc->BitBlt(pos, iBmpBlock.At(blockType%COLORNUM)); 
			} 
			xPos += 9; 
		} 
		yPos += 10; 
	} 
 
	// draw Info 
	const CFont* font; 
	font = CEikonEnv::Static()->NormalFont(); 
	aBackBufferGc->UseFont(font); 
	aBackBufferGc->SetPenColor(TRgb(215, 136, 20)); 
	aBackBufferGc->SetBrushStyle(CGraphicsContext::ENullBrush); 
 
	TBuf<6> info; 
	// score 
	info.Num(iStateScore); 
	aBackBufferGc->DrawText(info, TRect(TPoint(122, 90), TSize(45, 15)), 15, CGraphicsContext::ECenter, 0); 
	// line 
	info.Num(iLine); 
	aBackBufferGc->DrawText(info, TRect(TPoint(122, 118), TSize(45, 15)), 15, CGraphicsContext::ECenter, 0); 
	// Level 
	info.Num(iLevel); 
	aBackBufferGc->DrawText(info, TRect(TPoint(122, 145), TSize(45, 15)), 15, CGraphicsContext::ECenter, 0); 
 
	aBackBufferGc->DiscardFont(); 
 
	// draw Next Block 
	aBackBufferGc->SetBrushStyle(CGraphicsContext::ESolidBrush); 
	aBackBufferGc->SetBrushColor(KRgbBlack); 
	yPos = 29; 
	for(i = 0; i < 4; i++) 
	{ 
		xPos = 130; 
		for(j = 0; j < 4; j++) 
		{ 
			if((iBlockNext.RowMask(i) & (1<<(3-j)))) 
				aBackBufferGc->DrawRect(TRect(TPoint(xPos, yPos), TSize(6, 6))); 
			xPos += 7; 
		} 
		yPos += 7; 
	} 
} 
 
//////////////////////////////////////////////////////////////////////////////// 
 
// Other Methods 
 
// MoveTo()			Move the Block to a new position if possible 
TBool CGameTetris::MoveTo(const TPoint& aNewPos) 
{ 
	if(iGrid.DoesCollide(iBlock, aNewPos)) 
		return 0; 
 
	iBlockPos = aNewPos;		// don't update View here to make Model Independent 
 
	return 1;					// Move successful 
} 
 
// Rotate() 
void CGameTetris::Rotate() 
{ 
	if(iStateRotateDir == 0) 
		iStateRotateDir = -1; 
	iBlock.Rotate(iStateRotateDir);		// default state , deasil 
 
	if(iGrid.DoesCollide(iBlock, iBlockPos)) 
		iBlock.Rotate( (TInt8)-iStateRotateDir );	// rotate back	 
} 
 
 
// NewBlock() 
void CGameTetris::NewBlock() 
{ 
	iBlock		= iBlockNext; 
	iBlockNext	= TBlock::RandomBlock(iSeed, iStateDifficulty); 
 
	iBlockPos     = TPoint(4, -3); 
} 
 
// StartNewGame() 
void CGameTetris::StartNewGame() 
{ 
	// Game State 
	iLevel				= 1; 
	iLine				= 0; 
	iStateScore			= 0; 
	//iStateRotateDir	= 0; 
	//iStateDifficulty	= 0; 
 
	// create new Grid 
	iGrid			= TGrid::NewGrid(); 
	// Start Lines 
	if(iStateStartLines) 
		StartLines(iStateStartLines); 
		//StartLines(18); 
	// create a block 
	iBlockNext	= TBlock::RandomBlock(iSeed, iStateDifficulty); 
 
	NewBlock(); 
 
	iDelay = 0; 
} 
 
// GetRowContent()			 
void CGameTetris::GetRowContent(TUint8 aRow, TFixedArray& aRowContent) 
{ 
	int i; 
 
	for(i = 0; i < KGridX; i++) 
	{ 
		if(IsBlock(TPoint(i, aRow)))  
			aRowContent[i] = iBlock.Type(); 
		else  
			aRowContent[i] = iGrid.iContent[aRow][i]; 
	} 
} 
 
// if the position is a block 
TBool CGameTetris::IsBlock(const TPoint& aPos) const 
{ 
	if(TRect(iBlockPos, TSize(4, 4)).Contains(aPos)) 
		return (iBlock.RowMask(aPos.iY-iBlockPos.iY) & (1<<(3-aPos.iX+iBlockPos.iX))) > 0; 
 
	return false; 
} 
 
// FixBlock()	-- fix the block  -- be called if the current block can't move  
// @ return 0	-- game over 
// @ return 1	-- continue game and put the block into the content 
TBool CGameTetris::FixBlock() 
{ 
	TInt i; 
	// check if it is outside the board 
	for (i = 0; i < -iBlockPos.iY; i++) 
		if (iBlock.RowMask(i)) 
			return 0; 
 
	iGrid.PutBlock(iBlock, iBlockPos); 
		return 1; 
} 
 
//  
TInt CGameTetris::CheckRows() 
{ 
	TInt offset=0, i, j; 
 
	for (i = KGridY-1; i >= 0; i--) 
	{ 
		if (iGrid.iMask[i]==0xffffU) 
		{ 
			offset++; 
			iLine++; 
			continue; 
		} 
 
		if (offset > 0) 
		{ 
			iGrid.iMask[i+offset]=iGrid.iMask[i]; 
			for (j = 0; j < KGridX; j++) 
				iGrid.iContent[i+offset][j]=iGrid.iContent[i][j]; 
		} 
	} 
 
	for (i = 0; i < offset; i++) 
	{ 
		iGrid.iMask[i] = 0x003f; 
		for (j=0; j < KGridX; j++) 
			iGrid.iContent[i][j] = 0; 
	} 
 
	return offset;		// row's num to eliminate 
} 
 
void CGameTetris::Calculate(TInt rows) 
{ 
	switch(rows) 
	{ 
		case 1: 
		{ 
			iStateScore += 10; 
		}break; 
 
		case 2: 
		{ 
			iStateScore += 25; 
		}break; 
 
		case 3: 
		{ 
			iStateScore += 50; 
		}break; 
 
		case 4: 
		{ 
			iStateScore += 80; 
			iStateWellDone = ETrue; 
		}break; 
 
		default:break; 
	} 
	iStateClearRow = ETrue; 
	iStateScore += iStateDifficulty * 15; 
	iStateScore += iStateStartLines; 
	iStateScore += iLevel * 2; 
 
	if(iStateScore >= 500 * iLevel) 
	{ 
		iLevel++; 
		iStateLevelUp = ETrue; 
	} 
	if(iLevel > 10) 
	{ 
		iLevel = 0; 
		iStateDifficulty++; 
		iStateDifficulty %= 3; 
	} 
	 
} 
//  
void CGameTetris::LoadResL() 
{ 
	// Load bmps from mmp file 
	_LIT(KPathName, "\\System\\Apps\\Tetris\\images.mbm"); 
	 
	CEikonEnv* eikonEnv = CEikonEnv::Static(); 
	 
	// Load Blocks 
	iBmpBlock.At(0) = eikonEnv->CreateBitmapL(KPathName, EMbmImages1); 
	iBmpBlock.At(1) = eikonEnv->CreateBitmapL(KPathName, EMbmImages2); 
	iBmpBlock.At(2) = eikonEnv->CreateBitmapL(KPathName, EMbmImages3); 
	iBmpBlock.At(3) = eikonEnv->CreateBitmapL(KPathName, EMbmImages4); 
	iBmpBlock.At(4) = eikonEnv->CreateBitmapL(KPathName, EMbmImages5); 
	iBmpBlock.At(5) = eikonEnv->CreateBitmapL(KPathName, EMbmImages6); 
	iBmpBlock.At(6) = eikonEnv->CreateBitmapL(KPathName, EMbmImages7); 
	iBmpBlock.At(7) = eikonEnv->CreateBitmapL(KPathName, EMbmImages8); 
	iBmpBlock.At(8) = eikonEnv->CreateBitmapL(KPathName, EMbmImages9); 
	// Load background 
	iBmpBackground = eikonEnv->CreateBitmapL(KPathName, EMbmImagesBackground24); 
} 
 
void CGameTetris::StartLines(TUint8 aLines) 
{ 
	if(aLines >= 19) 
		return ; 
	 
	TInt i, j; 
	for(i = KGridY - 1; i >= KGridY - aLines; --i) 
	{ 
		for(j = 0; j < KGridX; ++j) 
		{ 
			TInt content = Math::Rand(iSeed) % 2; 
			if(content) 
			{ 
				iGrid.iContent[i][j] = (TInt8)(Math::Rand(iSeed) % BLOCKNUM + 1); 
			 
				iGrid.iMask[i] |= (1 << (15 - j)); 
			} 
		} 
	} 
 
}