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)); } } } }