📄 mopoidgameengine.cpp
字号:
// Store the sound we're about to play so that we will only start one
// sound in case more than one things happen at the same time.
TMopoidSounds playSound = ENumSounds;
// Move to a new temponary pos
//if (iBall.Move(iThisFrameStep))
// playSound = ESoundHit;
// Do not play a sound for a wall collision for now
iBall.Move(iThisFrameStep);
// Check collision with panel
if (iBall.CheckPanelCollision(iPanel, iThisFrameStep))
playSound = ESoundBounce;
// Check collision with bricks
TBrick::TBrickType brickColl = iBall.CheckBrickCollisionL(iGrid,
iThisFrameStep, TBall::ECenter);
// Also do a collision check for both sides of the ball, if no hit was found yet.
// As we only handle one collision at once, we still check the center of the ball first to make
// sure the main brick is hit when it's not clear which one is the main target.
if (brickColl == TBrick::EBrickInactive)
{
brickColl = iBall.CheckBrickCollisionL(iGrid, iThisFrameStep,
TBall::ELeft);
if (brickColl == TBrick::EBrickInactive)
{
brickColl = iBall.CheckBrickCollisionL(iGrid, iThisFrameStep,
TBall::ERight);
}
}
// Check if a brick has been removed.
if (brickColl == TBrick::EBrickNormal)
{
// Brick has been destroyed!
iSettings->iScore += iSettings->iBlockNormalDestroyScore;
}
if (iGrid->GetNumBricks() == 0)
{
// Played through level...
if (iSettings->iLevel < iSettings->iAvailableLevels)
{
// We've got another level...
iSettings->iGameStatus = CMopoidSettings::ENewLevel;
iSettings->iLevel ++;
iSettings->iScore += iSettings->iScoreLevelCleared;
iLevels.LoadLevelL(iFs, (iSettings->iLevel), iGrid, iSettings);
SetScreenSize(iSettings->iScreenSize);
PauseGame();
ResetBallAndPanel();
}
else
{
// Played through game
iSettings->iGameStatus = CMopoidSettings::EFinished;
iSettings->iScore += iSettings->iScoreGameFinished;
PauseGame();
}
}
// If any brick was hit (doesn't matter if it was destroyed), play a sound
if (brickColl != TBrick::EBrickInactive)
playSound = ESoundHit;
// Let's play the sound!
if (playSound != ENumSounds)
{
TRAPD(error, iSoundManager->PlayL(playSound))
;
}
// Check if we're still alive
if (iBall.CheckDeath(iPanel))
{
// No, the ball has passed below the lower border.
PauseGame();
iSettings->iLives --;
iSettings->iScore += iSettings->iScoreLiveLost;
// Check if game is over.
if (iSettings->iLives == 0)
iSettings->iGameStatus = CMopoidSettings::EDied;
else
iSettings->iGameStatus = CMopoidSettings::ELifeLost;
}
// Copy temp pos to real pos
iBall.ConvertToPos();
}
// -----------------------------------------------------------------------
const TPoint CMopoidGameEngine::ConvToScreenCoord(const TPoint& aGameCoord) const
{
return TPoint( (TInt)((aGameCoord.iX - iSettings->iGameRectX)
/ iSettings->iGameRectWidth * iSettings->iDrawRectWidth
+ iSettings->iDrawRectX), (TInt)((aGameCoord.iY
- iSettings->iGameRectY) / iSettings->iGameRectHeight
* iSettings->iDrawRectHeight + iSettings->iDrawRectY));
}
// -----------------------------------------------------------------------
void CMopoidGameEngine::DrawFrame() const
{
if (!iBackBufferBmpGc)
return;
// Clear back buffer
iBackBufferBmpGc->SetPenStyle(CGraphicsContext::ENullPen);
iBackBufferBmpGc->SetBrushColor(KRgbBlack);
iBackBufferBmpGc->SetBrushStyle(CGraphicsContext::ESolidBrush);
iBackBufferBmpGc->DrawRect(iSettings->iScreenRect);
//iBackBufferBmpGc->SetBrushColor( KRgbBlack);
//iBackBufferBmpGc->DrawRect(iSettings->iDrawRect);
// Set brush style to none so that transparency is drawn as transparent and not with a color (!)
iBackBufferBmpGc->SetBrushStyle(CGraphicsContext::ENullBrush);
// Put ball first, so that it is behind other objects should it be that at any time
TPoint ballSpritePos(iBall.iPos.iX - iSettings->iBallSizeHalf.iWidth,
iBall.iPos.iY - iSettings->iBallSizeHalf.iHeight);
// TODO: Draw ball
iBackBufferBmpGc->BitBltMasked(ConvToScreenCoord(ballSpritePos),
iSpriteHandler->GetSprite(MopoidShared::ESpriteBall),
iSpriteHandler->GetSprite(MopoidShared::ESpriteBall)->SizeInPixels(),
iSpriteHandler->GetSprite(MopoidShared::ESpriteBallM), EFalse);
// Draw bricks
for (TInt x=0; x<iSettings->iGridCols; x++)
{
for (TInt y=0; y<iSettings->iGridRows; y++)
{
// Check if there is a brick to draw at this position
if (iGrid->DrawBrickAtPos(x, y))
{
// Draw according bitmap.
MopoidShared::TSpriteIds spriteId;
switch (iGrid->GetBrickTypeAtPos(x, y))
{
case TBrick::EBrickNormal:
spriteId = MopoidShared::ESpriteBrickNormal;
break;
case TBrick::EBrickDouble:
spriteId = MopoidShared::ESpriteBrickDouble;
break;
case TBrick::EBrickIndestructible:
spriteId = MopoidShared::ESpriteBrickIndestructible;
break;
case TBrick::EBrickMoving:
spriteId = MopoidShared::ESpriteBrickMoving;
break;
case TBrick::EBrickHarderBrick:
spriteId = MopoidShared::ESpriteBrickHarderBrick;
break;
case TBrick::EBrickSofterBrick:
spriteId = MopoidShared::ESpriteBrickSofterBrick;
break;
default:
spriteId = MopoidShared::ESpriteBrickNormal;
}
// TODO: Draw bricks
iBackBufferBmpGc->BitBlt(
ConvToScreenCoord(iGrid->ConvertGridToXY(x, y)),
iSpriteHandler->GetSprite(spriteId));
}
}
}
// TODO: Draw Panel
iBackBufferBmpGc->BitBltMasked(ConvToScreenCoord(iPanel.iPos),
iSpriteHandler->GetSprite(MopoidShared::ESpritePanel),
iSpriteHandler->GetSprite(MopoidShared::ESpritePanel)->SizeInPixels(),
iSpriteHandler->GetSprite(MopoidShared::ESpritePanelM), EFalse);
TRAPD(err, DrawTextL());
}
// -----------------------------------------------------------------------
void CMopoidGameEngine::DrawTextL() const
{
// HUD
iBackBufferBmpGc->SetPenStyle(CGraphicsContext::ESolidPen);
iBackBufferBmpGc->SetPenColor(KRgbRed);
iBackBufferBmpGc->UseFont(iSettings->iFontUsed);
TBuf<30> tempStr;
CEikonEnv* env = CEikonEnv::Static();
const TInt yTextStartBottom = iSettings->iDrawRect.iTl.iY
- iSettings->iTextBaselineOffset;
// High Score
env->ReadResourceL(tempStr, R_HIGHSCORE);
tempStr.AppendNum(iSettings->iHighScore);
iBackBufferBmpGc->DrawText(tempStr, TPoint(5, yTextStartBottom));
// Score
env->ReadResourceL(tempStr, R_SCORE);
tempStr.AppendNum(iSettings->iScore);
iBackBufferBmpGc->DrawText(tempStr, TPoint(5, yTextStartBottom
- iSettings->iTextYOffset));
// Level
env->ReadResourceL(tempStr, R_LEVEL);
tempStr.AppendNum(iSettings->iLevel);
iBackBufferBmpGc->DrawText(tempStr, iSettings->iScreenRect,
yTextStartBottom, CGraphicsContext::ERight, 3);
// Lives
env->ReadResourceL(tempStr, R_LIVES);
tempStr.AppendNum(iSettings->iLives);
iBackBufferBmpGc->DrawText(tempStr, iSettings->iScreenRect,
yTextStartBottom - iSettings->iTextYOffset,
CGraphicsContext::ERight, 3);
// TODO: Uncomment code block
// Draw a line between status messages and play area
iBackBufferBmpGc->DrawLine(iSettings->iDrawRect.iTl, TPoint(
iSettings->iDrawRect.iBr.iX, iSettings->iDrawRect.iTl.iY));
// Draw a line at the right and left border
if (iSettings->iDrawRect.iTl.iX > 0)
{
iBackBufferBmpGc->DrawLine(iSettings->iDrawRect.iTl, TPoint(
iSettings->iDrawRect.iTl.iX, iSettings->iDrawRect.iBr.iY));
iBackBufferBmpGc->DrawLine(iSettings->iDrawRect.iBr, TPoint(
iSettings->iDrawRect.iBr.iX, iSettings->iDrawRect.iTl.iY));
}
// Title
iBackBufferBmpGc->SetPenColor(TRgb(240, 200, 50));
env->ReadResourceL(tempStr, R_TITLE);
iBackBufferBmpGc->DrawText(tempStr, iSettings->iScreenRect,
iSettings->iTextYOffset, CGraphicsContext::ECenter, 3);
// Status messages
TBool displayStatus = ETrue;
switch (iSettings->iGameStatus)
{
case CMopoidSettings::ELifeLost:
{
env->ReadResourceL(tempStr, R_LIFELOST);
}
break;
case CMopoidSettings::EDied:
{
env->ReadResourceL(tempStr, R_GAMEOVER);
}
break;
case CMopoidSettings::EStarted:
case CMopoidSettings::ENewLevel:
{
env->ReadResourceL(tempStr, R_ENTERLEVEL);
tempStr.AppendNum(iSettings->iLevel);
break;
}
case CMopoidSettings::EFinished:
{
env->ReadResourceL(tempStr, R_FINISHED);
}
break;
default:
displayStatus = EFalse;
}
// If there is a status message to display, show it to the user.
if (displayStatus)
{
iBackBufferBmpGc->SetPenColor(KRgbRed);
iBackBufferBmpGc->UseFont(CEikonEnv::Static()->TitleFont());
iBackBufferBmpGc->DrawText(tempStr, iSettings->iScreenRect,
iSettings->iScreenRect.Height() / 4 * 3, CGraphicsContext::ECenter);
}
}
// -----------------------------------------------------------------------
void CMopoidGameEngine::PauseGame()
{
// Update highscore
if (iSettings->iScore > iSettings->iHighScore)
{
iSettings->iHighScore = iSettings->iScore;
TRAPD(err, SaveGameProgressL())
;
}
iSettings->iGamePaused = ETrue;
// Stop the timer. The active object will be stopped by the DoFrame-function
// after the next update.
StopTimer();
}
// -----------------------------------------------------------------------
void CMopoidGameEngine::ResumeGameL()
{
if (iSettings->iGameStatus == CMopoidSettings::EFinished
|| iSettings->iGameStatus == CMopoidSettings::EDied)
{
// Don't resume the game, we've already played through it / we're dead.
return;
}
// Make sure that the pause does not affect the regular score decrease interval
TTime curFrameTime;
curFrameTime.UniversalTime();
TTimeIntervalMicroSeconds tStepMicroS =
curFrameTime.MicroSecondsFrom(iLastFrameTime);
iLastScoreDecreaseTime += tStepMicroS;
iLastFrameTime.UniversalTime();
iSettings->iGamePaused = EFalse;
// If we were waiting for the user to do something, switch back to
// the normal play-mode
if (iSettings->iGameStatus == CMopoidSettings::EStarted
|| iSettings->iGameStatus == CMopoidSettings::ENewLevel
|| iSettings->iGameStatus == CMopoidSettings::ELifeLost)
{
ResetBallAndPanel();
iSettings->iGameStatus = CMopoidSettings::EPlaying;
}
// Start the point-decreasing + backlight timer
StartTimerL();
}
//------------------------------------------------------------------------------
void CMopoidGameEngine::SaveGameProgressL()
{
// Add the path to the filename
RBuf fileName;
fileName.CleanupClosePushL();
// TODO: Add the private directoy to the filename and store
// the complete URI in the fileName descriptor.
// The name of the file itself is stored in KMopoidDataFile.
NCommonFunctions::AddPrivateDirL(iFs, KMopoidDataFile, fileName);
// TODO: Open a file store
CFileStore* store = CDirectFileStore::ReplaceLC(iFs, fileName, EFileWrite);
store->SetTypeL(KDirectFileStoreLayoutUid);
// TODO: Create the stream
RStoreWriteStream stream;
TStreamId id = stream.CreateLC(*store);
// TODO: Write file version number
stream.WriteInt32L(MOPOID_FILE_VERSION_NUMBER);
// TODO: Write highscore
stream.WriteInt32L(iSettings->iHighScore);
// TODO: Write sound level (later step)
stream.WriteInt32L(iSettings->iSoundLevel);
// TODO: Commit the changes to the stream
stream.CommitL();
CleanupStack::PopAndDestroy(&stream);
// TODO: Set the stream in the store and commit the store
store->SetRootL(id);
store->CommitL();
CleanupStack::PopAndDestroy(store);
CleanupStack::PopAndDestroy(&fileName);
}
//------------------------------------------------------------------------------
void CMopoidGameEngine::LoadGameProgressL()
{
RBuf fileName;
fileName.CleanupClosePushL();
// TODO: Add the private directoy to the filename and store
// the complete URI in the fileName descriptor.
// The name of the file itself is stored in KMopoidDataFile.
NCommonFunctions::AddPrivateDirL(iFs, KMopoidDataFile, fileName);
// TODO: Open the file store in read mode
CFileStore* store = CDirectFileStore::OpenLC(iFs, fileName, EFileRead);
// TODO: Open the data stream inside the store
RStoreReadStream stream;
stream.OpenLC(*store, store->Root());
// TODO: Read all the data
TInt versionNumber = stream.ReadInt32L();
if (versionNumber != MOPOID_FILE_VERSION_NUMBER)
User::Leave(KErrNotFound);
iSettings->iHighScore = stream.ReadInt32L();
iSettings->iSoundLevel = stream.ReadInt32L();
// TODO: Delete all the remaining stuff on the cleanup stack
// (store, stream)
CleanupStack::PopAndDestroy(&stream);
CleanupStack::PopAndDestroy(store);
CleanupStack::PopAndDestroy(&fileName);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -