CEngine.cpp
上传用户:snevogroup
上传日期:2008-06-06
资源大小:432k
文件大小:13k
源码类别:

Symbian

开发平台:

C/C++

  1. #include <eikenv.h>
  2. #include <fbs.h>
  3. #include <aknutils.h>
  4. #include <s32file.h>
  5. #include <aknquerydialog.h> 
  6. #include <bautils.h>
  7. #include "CEngine.h"
  8. #include "CGameTimer.h"
  9. #include "CSplash.h"
  10. #include "CMenu.h"
  11. #include "CGameTetris.h"
  12. #include "TetrisAppUi.h"
  13. #include <Tetris.rsg>
  14. #include "Tetris.hrh"
  15. #include "TScore.h"
  16. // sound
  17. #include "CWaveLoader.h"
  18. #include "CSoundMixer.h"
  19. _LIT(KFileStore,"save.dat");
  20. // construct and destruct
  21. // NewL()
  22. CEngine* CEngine::NewL( CGameTetris* aGame, CWindowGc& aGc, RWindow& aWindow, TDisplayMode aDisplayMode )
  23. {
  24. CEngine* self = new( ELeave )CEngine(aGame, aGc, aWindow, aDisplayMode );
  25. CleanupStack::PushL( self );
  26. self->ConstructL();
  27. CleanupStack::Pop( self );
  28. return self;
  29. }
  30. // ~
  31. CEngine::~CEngine()
  32. {
  33. if(iTimer)
  34. {
  35. iTimer->Cancel();
  36. delete iTimer;
  37. }
  38. delete iBackBufferGc;
  39. delete iBackBufferDevice;
  40. delete iBackBufferBitmap; 
  41. delete iMenu;
  42. delete iBitmapUtil;
  43. delete iScoreTable;
  44. // sound
  45. delete iSound;
  46. delete iSoundBg.iData;
  47. delete iSoundGameOver.iData;
  48. delete iSoundOnClick.iData;
  49. delete iSoundMenu.iData;
  50. delete iSoundClearRow.iData;
  51. delete iSoundWellDone.iData;
  52. delete iSoundLevelUp.iData;
  53. }
  54. // ConstructL()
  55. void CEngine::ConstructL()
  56. {
  57. // get the draw region
  58. TPoint pos = iWindow.Position();
  59. TSize size = iWindow.Size();
  60. iDrawRect.SetRect(pos, size);
  61. // Create a new bitmap with size of view’s rect and color depth of
  62. // screen
  63. iBackBufferBitmap = new(ELeave) CFbsBitmap();
  64. User::LeaveIfError(iBackBufferBitmap->Create(iDrawRect.Size(), iDisplayMode));
  65. // Create bitmap device for the bitmap
  66. iBackBufferDevice = CFbsBitmapDevice::NewL(iBackBufferBitmap);
  67. // Create graphics context for the bitmap
  68. User::LeaveIfError(iBackBufferDevice->CreateContext(iBackBufferGc));
  69. iBitmapUtil = new(ELeave)TBitmapUtil(iBackBufferBitmap);
  70. // Create a menu
  71. iMenu = CMenu::NewL(iBackBufferGc);
  72. iTimer = CGameTimer::NewL(*this);
  73. iPause = ETrue;
  74. // Load sound
  75. CWavLoader* wavLoader = CWavLoader::NewLC();
  76. iSoundBg = wavLoader->LoadL(_L("bg.wav"));
  77. iSoundGameOver = wavLoader->LoadL(_L("gameover.wav"));
  78. iSoundOnClick = wavLoader->LoadL(_L("click.wav"));
  79. iSoundMenu = wavLoader->LoadL(_L("menu.wav"));
  80. iSoundClearRow = wavLoader->LoadL(_L("cleanrow.wav"));
  81. iSoundLevelUp = wavLoader->LoadL(_L("levelup.wav"));
  82. iSoundWellDone = wavLoader->LoadL(_L("welldone.wav"));
  83. CleanupStack::PopAndDestroy( wavLoader );
  84. // create sound mixer
  85. iSound = CSoundMixer::NewL();
  86. // make iSoundBg repeat itself
  87. iSoundBg.iRepEnd = iSoundBg.iLength;
  88. //iSound->Play(iSoundBg, 0, 16000, 256);
  89. // create score table
  90. iScoreTable = new (ELeave) CArrayFixSeg<TScore>(1);
  91. ScoreLoadL();
  92. iGameState = ENewSplash;
  93. //iGameState = EMenu;
  94. }
  95. // CEngine()
  96. CEngine::CEngine( CGameTetris* aGame, CWindowGc& aGc, RWindow& aWindow, TDisplayMode aDisplayMode )
  97. : iGame(aGame)
  98. , iGc( aGc )
  99. , iWindow( aWindow )
  100. , iDisplayMode( aDisplayMode )
  101. {}
  102. ///////////////////////////////////////////////////////////////////////////////////
  103. // Other Method 
  104. // DoGameFrameL()
  105. TInt CEngine::DoGameFrameL()
  106. {
  107. // Prepare to Splash
  108. if(iGameState == ENewSplash)
  109. {
  110. if(!ShowSplash())
  111. iGameState = EMenu;
  112. }
  113. if(iGameState == EExit)
  114. {
  115. if(!ShowSplash())
  116. {
  117. CTetrisAppUi* appUi = static_cast<CTetrisAppUi*> (CEikonEnv::Static()->AppUi());
  118. appUi->Quit();
  119. //User::Exit(0); // this cann't check memory leak ,why create it ,i'm confused!
  120. }
  121. }
  122. // Prepare for showing the menu, used for state changing.
  123. if(iGameState == EMenu)
  124. {
  125. // Stop bg music
  126. iSound->Stop(0);
  127. // set Menu running frequency
  128. iTimer->SetTickTime(40000);
  129. iGameState = EMenuRunning;
  130. }
  131. // Menu running
  132. if(iGameState == EMenuRunning)
  133. {
  134. // show main menu
  135. TInt32 signal = iMenu->Command(iKey);
  136. switch(signal)
  137. {
  138. case 1 : // quit
  139. {
  140. iGameState = EExit;
  141. }break;
  142. case 2 : // Start new game
  143. {
  144. if(!iMusicOff)
  145. iSound->Play(iSoundBg, 0, 16000, 64);
  146. iGameState = ERunning;
  147. iGame->iStateRunning = 0;
  148. iTimer->SetTickTime(50000);
  149. }break;
  150. case 3 : // continue game
  151. {
  152. if(!iMusicOff)
  153. iSound->Play(iSoundBg, 0, 16000, 64);
  154. if(!iGame->iStateRunning)
  155. return 1;
  156. iGameState = ERunning;
  157. iTimer->SetTickTime(50000);
  158. }break;
  159. case 4:
  160. {
  161. iDisplayTop5 = 1;
  162. }break;
  163. case 5:
  164. {
  165. iDisplayTop5 = 0;
  166. }break;
  167. case 11 : // Set brick rotation
  168. {
  169. if(iMenu->iSetting[0] == 0)
  170.   iGame->iStateRotateDir = -1;
  171. else
  172. iGame->iStateRotateDir = 1;
  173. }break;
  174. case 12 : // Set Sound
  175. {
  176. if(iMenu->iSetting[1] == 2) // set sound effect
  177. iSoundEffectOff = 0;
  178. else
  179. iSoundEffectOff = 1;
  180. if(iMenu->iSetting[2] == 4) // set background music
  181. iMusicOff = 0;
  182. else
  183. iMusicOff = 1;
  184. iSound->SetVolume( (iMenu->iSetting[3] - 5) * 256 / 4 );
  185. }break;
  186. case 13 : // Set Difficult
  187. {
  188. // start lines, scratching
  189. iGame->iStateStartLines = static_cast<TUint8> ((iMenu->iSetting[4] - 10) * 5);
  190. // Difficulty
  191. iGame->iStateDifficulty = static_cast<TUint8> (iMenu->iSetting[5] - 14);
  192. }break;
  193. default:
  194. {
  195. iGc.Activate( iWindow );
  196. iMenu->Draw();
  197. iGc.BitBlt(iDrawRect.iTl, iBackBufferBitmap);
  198. if(iDisplayTop5)
  199. ScoreDisplay();
  200. iGc.Deactivate();
  201. }break;
  202. }
  203. iKey = 0;
  204. }
  205. // game over
  206. if(iGameState == EGameOver)
  207. {
  208. // show Txt "game over" and some other effects
  209. // check if it is a new high score
  210. // if it is, then prompt to input user's name
  211. // else goto main menu directly
  212. iBitmapUtil->Begin(TPoint(0, 0)); // lock the heap
  213. TUint16* addr = (TUint16*)iBackBufferBitmap->DataAddress();
  214. // width and height in pixel 
  215. TInt width = iBackBufferBitmap->SizeInPixels().iWidth;
  216. TInt height = iBackBufferBitmap->SizeInPixels().iHeight;
  217. if(!iControl)
  218. DipBlackwhite(addr, width, height);
  219. if(++iControl > 15)
  220. DipEffect(addr, width, height);
  221. iBitmapUtil->End(); // unlock the heap
  222. if(iControl == 35)
  223. {
  224. iControl = 0;
  225. iGameState = EMenu;
  226. ScoreAddL();
  227. return 1;
  228. }
  229. iGc.Activate( iWindow );
  230. iGc.BitBlt(TPoint(0, 0), iBackBufferBitmap);
  231. const CFont* font;
  232. font = CEikonEnv::Static()->LegendFont();
  233. iGc.UseFont(font);
  234. iGc.SetPenColor(KRgbRed);
  235. iGc.DrawText(_L("Game Over"), TPoint(65, 100));
  236. iGc.DiscardFont();
  237. iGc.Deactivate();
  238. iKey = 0;
  239. }
  240. // running
  241. if(iGameState == ERunning)
  242. {
  243. TInt8 state = iGame->Run();
  244. if(state == 1) // game over
  245. {
  246. if(!iSoundEffectOff)
  247. iSound->Play(iSoundGameOver, 1, 16000, 64);
  248. iGameState = EGameOver;
  249. return 1;
  250. }
  251. // draw screen
  252. if(iGame->Command(iKey) || state == 2)
  253. {
  254. iGc.Activate( iWindow );
  255. iGame->Draw(iBackBufferGc);
  256. iGc.BitBlt(iDrawRect.iTl, iBackBufferBitmap);
  257. iGc.Deactivate();
  258. }
  259. iKey = 0;
  260. // play sound effect
  261. if(!iSoundEffectOff)
  262. {
  263. // only play one sound effect ,there is a priority
  264. if(iGame->iStateLevelUp)
  265. {
  266. iSound->Play(iSoundLevelUp, 1, 16000, 64);
  267. iGame->iStateLevelUp = 0;
  268. //return 1;
  269. }
  270. if(iGame->iStateWellDone)
  271. {
  272. iSound->Play(iSoundWellDone, 2, 16000, 64);
  273. iGame->iStateWellDone = 0;
  274. }
  275. if(iGame->iStateClearRow)
  276. {
  277. iSound->Play(iSoundClearRow, 3, 16000, 64);
  278. iGame->iStateClearRow = 0;
  279. //return 1;
  280. }
  281. }
  282. }
  283. return ETrue;
  284. }
  285. // Start()
  286. void CEngine::Start()
  287. {
  288. if( !iPause ) 
  289. return;
  290. iPause = EFalse;
  291. iTimer->Start();
  292. iSound->Resume();
  293. }
  294. // Stop()
  295. void CEngine::Stop()
  296. {
  297. if( iPause ) 
  298. return;
  299. iPause = ETrue;
  300. iTimer->Cancel();
  301. iSound->Pause();
  302. }
  303. // Pause()
  304. void CEngine::Pause()
  305. {
  306. if(iPause)
  307. Start();
  308. else
  309. Stop();
  310. }
  311. // Command()
  312. void CEngine::Command(TInt aCommand)
  313. {
  314. if(aCommand == 'q')
  315. {
  316. if(iGameState == ERunning || iGameState == EMenuRunning)
  317. iGameState = EMenu;
  318. else
  319. return;
  320. }
  321. if(aCommand == '0' && iGameState == ERunning)
  322. Pause();
  323. iKey = aCommand;
  324. if(iSoundEffectOff)
  325. return;
  326. if(iGameState == EMenuRunning)
  327. {
  328. switch(iKey)
  329. {
  330. case EStdKeyDevice5:
  331. case '5':
  332. case 63557:
  333. {
  334. iSound->Play(iSoundOnClick, 2, 16000, 64);
  335. }break;
  336. case EKeyUpArrow : // UP
  337. case '2' :
  338. case EKeyDownArrow : // Down
  339. case '8' :
  340. case EKeyLeftArrow : // Left
  341. case '4' :
  342. case EKeyRightArrow : // Right
  343. case '6' :
  344. {
  345. iSound->Play(iSoundMenu, 3, 16000, 64);
  346. }break;
  347. default:
  348. break;
  349. }
  350. }
  351. }
  352. // ShowSplash()
  353. TBool CEngine::ShowSplash()
  354. {
  355. if(!iSplash)
  356. {
  357. iSplash = CSplash::NewL(iGc, iWindow);
  358. iTimer->SetTickTime(100000);
  359. }
  360. else if(!iSplash->Draw())
  361. {
  362. delete iSplash;
  363. iSplash = NULL;
  364. return 0; // stop splashing
  365. }
  366. return 1; // keep splashing
  367. }
  368. // DipEffect()
  369. void CEngine::DipEffect(TUint16* aAddr, TInt aWidthInPixel, TInt aHeightInPixel)
  370. {
  371. TInt i, j;
  372. TUint16* index;
  373. for(i = 0; i < aHeightInPixel; i++)
  374. {
  375. index = aAddr + aWidthInPixel * i; // get address of each row
  376. for(j = 0; j < aWidthInPixel; j++)
  377. {
  378. TInt8 r = static_cast<TInt8> (*index  & 0x00f);
  379.             TInt8 g = static_cast<TInt8> ((*index & 0x0f0) >> 4);
  380.             TInt8 b = static_cast<TInt8> ((*index & 0xf00) >> 8);
  381. r--;
  382. g--;
  383. b--;
  384. (r < 0) ? *index  = 0     : *index  = r;
  385.             (g < 0) ? *index &= 0xf0f : *index |= g << 4;
  386.             (b < 0) ? *index &= 0x0ff : *index |= b << 8;
  387. //(r > 0xf) ? *index  = 0xf   : *index  = r;
  388.             //(g > 0xf) ? *index |= 0x0f0 : *index |= g << 4;
  389.             //(b > 0xf) ? *index |= 0xf00 : *index |= b << 8;
  390. index ++;
  391. }
  392. }
  393. }
  394. void CEngine::DipBlackwhite(TUint16* aAddr, TInt aWidthInPixel, TInt aHeightInPixel)
  395. {
  396. TInt i, j;
  397. TUint16* index;
  398. for(i = 0; i < aHeightInPixel; i++)
  399. {
  400. index = aAddr + aWidthInPixel * i; // get address of each row
  401. for(j = 0; j < aWidthInPixel; j++)
  402. {
  403. *index = *index > 0x800 ? 0xfff : 0;
  404. index ++;
  405. }
  406. }
  407. }
  408. // method deal with score
  409. void CEngine::ScoreLoadL()
  410. {
  411. // in my opinion, this can only be used in real handset, not emulator
  412. TFileName fileName( KFileStore );
  413. CompleteWithAppPath( fileName );
  414. if(!BaflUtils::FileExists(CEikonEnv::Static()->FsSession(), fileName))
  415. {
  416. ScoreSaveL();
  417. return;
  418. }
  419. CFileStore* store = CDirectFileStore::OpenLC(CEikonEnv::Static()->FsSession(), fileName, EFileRead);
  420. RStoreReadStream stream;
  421. stream.OpenLC(*store,store->Root());
  422.  
  423. TScore sc;
  424. TInt i, count=stream.ReadInt32L();
  425. for(i = 0; i < count; i++)
  426. {
  427. stream >> sc;
  428. iScoreTable->AppendL(sc);
  429. }
  430. CleanupStack::PopAndDestroy(2); // (store and stream)
  431. }
  432. void CEngine::ScoreAddL()
  433. {
  434. // first clear score table
  435. ScoreReset();
  436. // load score
  437. ScoreLoadL();
  438. // check if the score is a new Top5 score
  439.   if(iScoreTable->Count() == TopNum) // not full
  440. if(iGame->iStateScore <= -iScoreTable->At(TopNum - 1).iValue)
  441. return;
  442. TBuf<15> name;
  443. CAknTextQueryDialog* dialog = CAknTextQueryDialog::NewL(name);
  444. if(!dialog->ExecuteLD(R_INPUT_USERNAME_DIALOG))
  445. return;
  446. // new score
  447. TScore newScore(iGame->iStateScore, name);
  448.     // Insert the element in the Score table (using an Integer key on iValue)
  449.     TKeyArrayFix byScore(_FOFF(TScore, iValue), ECmpTInt);
  450.     iScoreTable->InsertIsqAllowDuplicatesL(newScore, byScore);
  451.    
  452.     // Remove the last player from the table if necessary and compress the table
  453.     if(iScoreTable->Count() > TopNum)
  454.         iScoreTable->Delete(TopNum);
  455.     iScoreTable->Compress();
  456. // save the score
  457. ScoreSaveL();
  458. }
  459. void CEngine::ScoreSaveL()
  460. {
  461. // in my opinion, this can only be used in real handset, not emulator
  462. TFileName fileName( KFileStore );
  463. CompleteWithAppPath( fileName );
  464. CFileStore* store = CDirectFileStore::ReplaceLC(CEikonEnv::Static()->FsSession(), fileName, EFileWrite);
  465. store->SetTypeL(KDirectFileStoreLayoutUid);
  466. // Create the hi-score stream
  467. RStoreWriteStream stream;
  468. TStreamId id = stream.CreateLC(*store);
  469. // Write the number of score table entries in the store
  470. TInt count= iScoreTable->Count();
  471. stream.WriteInt32L(count);
  472. // Then write each entry
  473. for(TInt i = 0; i < count; i++)
  474. {
  475. stream << iScoreTable->At(i);
  476. }
  477. // Commit the changes to the stream
  478. stream.CommitL();
  479. CleanupStack::PopAndDestroy();
  480. // Set the stream in the store and commit the store
  481. store->SetRootL(id);
  482. store->CommitL();
  483. CleanupStack::PopAndDestroy();
  484. }
  485. void CEngine::ScoreDisplay()
  486. {
  487. // note this don't has iGc.Activate( iWindow ); & iGc.Deactivate();
  488. //iGc.Activate( iWindow );
  489. const CFont* font;
  490. font = CEikonEnv::Static()->TitleFont();
  491. iGc.UseFont(font);
  492. iGc.SetPenColor(KRgbWhite);
  493. iGc.DrawText(_L("Top 5"), TPoint(75, 30));
  494. for(TInt i = 0; i < iScoreTable->Count(); i++)
  495. {
  496. iGc.DrawText(iScoreTable->At(i).iName, TPoint(30, 60 + 30*i));
  497. TBuf16<10> score;
  498. score.Num(-iScoreTable->At(i).iValue);
  499. iGc.DrawText(score, TPoint(130, 60 + 30*i));
  500. }
  501. iGc.DiscardFont();
  502. //iGc.Deactivate();
  503. }
  504. void CEngine::ScoreReset()
  505. {
  506. iScoreTable->Delete(0, iScoreTable->Count());
  507. }