📄 lvtetrisengine.cpp
字号:
#include <e32base.h>
#include <eikenv.h>
#include <e32Math.h>
#include "LvtetrisEngine.h"
#include <lvtetris.mbg>
#include <lvtetris.rsg>
// construct and destruct
// NewL()
CLvtetrisEngine* CLvtetrisEngine::NewL()
{
CLvtetrisEngine* self = new (ELeave) CLvtetrisEngine;
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
// CLvtetrisEngine()
CLvtetrisEngine::CLvtetrisEngine() : iGrid()
{}
// ~
CLvtetrisEngine::~CLvtetrisEngine()
{
iBmpBlock.DeleteAll();
iBmpBlock.Reset();
delete iBmpBackground;
iBmpBackground = NULL;
iGamePauseInforTxt.DeleteAll();
iGamePauseInforTxt.Reset();
iGameOverInforTxt.DeleteAll();
iGameOverInforTxt.Reset();
}
void CLvtetrisEngine::ConstructL()
{
LoadResL();
// Make the seed
TTime time;
time.HomeTime();
iSeed = time.Int64();
}
////////////////////////////////////////////////////////////////////////////////
// Method
// handel all key relatively
TGameStatus CLvtetrisEngine::Command(TInt aCommand)
{
switch(aCommand)
{
case EKeyRightArrow : // right
case '6' :
{
MoveTo(iBlockPos + TPoint(1, 0));
}
break;
case EKeyLeftArrow : // left
case '4' :
{
MoveTo(iBlockPos + TPoint(-1, 0));
}
break;
case EKeyUpArrow : // up
case '2' :
case '5' :
case 63557 :
{
Rotate();
}
break;
case EKeyDownArrow : // down
case '8' :
{
while(MoveTo(iBlockPos + TPoint(0, 1)));
}
break;
case EKeyDevice1:
return GAMEMENUING;
default:
break;
}
return GAMERUNNING;
}
// move down the block automatic
TInt8 CLvtetrisEngine::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);
}
NewBlock(); // create a new one
}
flag = 2; // update view
}
iDelay = iDelay ? --iDelay : 5-iLevel;
}
return flag;
}
////////////////////////////////////////////////////////////////////////////////
// Other Methods
// MoveTo() Move the Block to a new position if possible
TBool CLvtetrisEngine::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 CLvtetrisEngine::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 CLvtetrisEngine::NewBlock()
{
iBlock = iBlockNext;
iBlockNext = TBlock::RandomBlock(iSeed, iStateDifficulty);
iBlockPos = TPoint(4, -3);
}
// StartNewGame()
void CLvtetrisEngine::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 CLvtetrisEngine::GetRowContent(TUint8 aRow, TFixedArray<TUint8, KGridX>& 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 CLvtetrisEngine::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 CLvtetrisEngine::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 CLvtetrisEngine::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 CLvtetrisEngine::Calculate(TInt rows)
{
switch(rows)
{
case 1:
{
iStateScore += 10;
}break;
case 2:
{
iStateScore += 25;
}break;
case 3:
{
iStateScore += 50;
}break;
case 4:
{
iStateScore += 80;
}break;
default:break;
}
iStateScore += iStateDifficulty * 15;
iStateScore += iStateStartLines;
iStateScore += iLevel * 2;
if(iStateScore >= 500 * iLevel)
{
iLevel++;
}
if(iLevel > 10)
{
iLevel = 0;
iStateDifficulty++;
iStateDifficulty %= 3;
}
}
void CLvtetrisEngine::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));
}
}
}
}
void CLvtetrisEngine::LoadResL()
{
// Load bmps from mmp file
_LIT(KPathName, "\\System\\Apps\\LvTetris\\Lvtetris.mbm");
CEikonEnv* eikonEnv = CEikonEnv::Static();
// Load Blocks
iBmpBlock.At(0) = eikonEnv->CreateBitmapL(KPathName, EMbmLvtetris1);
iBmpBlock.At(1) = eikonEnv->CreateBitmapL(KPathName, EMbmLvtetris2);
iBmpBlock.At(2) = eikonEnv->CreateBitmapL(KPathName, EMbmLvtetris3);
iBmpBlock.At(3) = eikonEnv->CreateBitmapL(KPathName, EMbmLvtetris4);
iBmpBlock.At(4) = eikonEnv->CreateBitmapL(KPathName, EMbmLvtetris5);
iBmpBlock.At(5) = eikonEnv->CreateBitmapL(KPathName, EMbmLvtetris6);
iBmpBlock.At(6) = eikonEnv->CreateBitmapL(KPathName, EMbmLvtetris7);
iBmpBlock.At(7) = eikonEnv->CreateBitmapL(KPathName, EMbmLvtetris8);
iBmpBlock.At(8) = eikonEnv->CreateBitmapL(KPathName, EMbmLvtetris9);
// Load background
//iBmpBackground = eikonEnv->CreateBitmapL(KPathName, EMbmLvtetrisBackground24);
iGamePauseInforTxt[0] = eikonEnv->AllocReadResourceL(R_GAME_PAUSE_LINE1);
iGamePauseInforTxt[1] = eikonEnv->AllocReadResourceL(R_GAME_PAUSE_LINE2);
iGameOverInforTxt[0] = eikonEnv->AllocReadResourceL(R_GAME_OVER_LINE1);
iGameOverInforTxt[1] = eikonEnv->AllocReadResourceL(R_GAME_OVER_LINE2);
iGamePauseInforPos[0] = TPoint(10,90);
iGamePauseInforPos[1] = TPoint(10,110);
iGameOverInforPos[0] = TPoint(10,90);
iGameOverInforPos[1] = TPoint(10,110);
}
void CLvtetrisEngine::DrawTetris(CFbsBitGc* aBackBufferGc)
{
TInt xPos, yPos;
TUint8 i, j;
// draw background
// aBackBufferGc->BitBlt(TPoint(0, 0), iBmpBackground);
// draw blocks
yPos = 0;
TFixedArray<TUint8, KGridX> 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;
}
}
void CLvtetrisEngine::DrawGamePauseInfor(CFbsBitGc* aBackBufferGc)
{
_LIT(KPauseFontName,"Roman");
CFont* pauseFont;
TFontSpec pauseFontSpec(KPauseFontName, 10);
pauseFontSpec.iFontStyle.SetStrokeWeight(EStrokeWeightBold);
CBitmapDevice* pausescreenDevice=CEikonEnv::Static()->ScreenDevice();
pausescreenDevice->GetNearestFontInPixels(pauseFont,pauseFontSpec);
aBackBufferGc->UseFont(pauseFont);
aBackBufferGc->SetPenColor(KRgbRed);
aBackBufferGc->DrawText(*iGamePauseInforTxt.At(0), iGamePauseInforPos[0]);
aBackBufferGc->DrawText(*iGamePauseInforTxt.At(1), iGamePauseInforPos[1]);
// delete created Font
aBackBufferGc->DiscardFont();
pausescreenDevice->ReleaseFont(pauseFont);
}
void CLvtetrisEngine::DrawGameOverInfor(CFbsBitGc* aBackBufferGc)
{
_LIT(KOverFontName,"Roman");
CFont* overFont;
TFontSpec overFontSpec(KOverFontName, 10);
overFontSpec.iFontStyle.SetStrokeWeight(EStrokeWeightBold);
CBitmapDevice* overscreenDevice=CEikonEnv::Static()->ScreenDevice();
overscreenDevice->GetNearestFontInPixels(overFont,overFontSpec);
aBackBufferGc->UseFont(overFont);
aBackBufferGc->SetPenColor(KRgbRed);
aBackBufferGc->DrawText(*iGameOverInforTxt.At(0), iGameOverInforPos[0]);
aBackBufferGc->DrawText(*iGameOverInforTxt.At(1), iGameOverInforPos[1]);
// delete created Font
aBackBufferGc->DiscardFont();
overscreenDevice->ReleaseFont(overFont);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -