HighScoreScreen.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // LoadingScreen.cs
  4. //
  5. // Microsoft XNA Community Game Platform
  6. // Copyright (C) Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #endregion
  9. #region Using Statements
  10. using System;
  11. using System.Collections.Generic;
  12. using System.IO;
  13. using System.IO.IsolatedStorage;
  14. using Microsoft.Xna.Framework;
  15. using Microsoft.Xna.Framework.Graphics;
  16. using Microsoft.Xna.Framework.Input.Touch;
  17. using Microsoft.Xna.Framework.Input;
  18. using Microsoft.Xna.Framework.GamerServices;
  19. #if !WINDOWS_PHONE
  20. using Microsoft.Xna.Framework.Storage;
  21. #endif
  22. #endregion
  23. namespace HoneycombRush
  24. {
  25. class HighScoreScreen : GameScreen
  26. {
  27. #region Fields/Properties
  28. static readonly string HighScoreFilename = "highscores.txt";
  29. #if WINDOWS_PHONE
  30. const int highscorePlaces = 5;
  31. #else
  32. const int highscorePlaces = 7;
  33. #endif
  34. public static List<KeyValuePair<string, int>> highScore = new List<KeyValuePair<string, int>>(highscorePlaces)
  35. {
  36. new KeyValuePair<string,int>
  37. ("Jasper",55000),
  38. new KeyValuePair<string,int>
  39. ("Ellen",52750),
  40. new KeyValuePair<string,int>
  41. ("Terry",52200),
  42. new KeyValuePair<string,int>
  43. ("Lori",50200),
  44. new KeyValuePair<string,int>
  45. ("Michael",50750),
  46. #if !WINDOWS_PHONE
  47. new KeyValuePair<string,int>
  48. ("Frodo",49550),
  49. new KeyValuePair<string,int>
  50. ("Chuck",46750),
  51. #endif
  52. };
  53. SpriteFont highScoreFont;
  54. Dictionary<int, string> numberPlaceMapping;
  55. Rectangle safeArea;
  56. public static bool HighscoreLoaded { get; private set; }
  57. public static bool HighscoreSaved { get; private set; }
  58. #if !WINDOWS_PHONE
  59. // These variables will be used to save/load the high score data asynchronously
  60. static bool shouldSaveHighScore;
  61. static bool savingHighscore;
  62. static bool loadingHighscore;
  63. static bool deviceSelectorLaunched;
  64. public static StorageDevice Storage { get; set; }
  65. #endif
  66. #endregion
  67. #region Initialzations
  68. static HighScoreScreen()
  69. {
  70. HighscoreLoaded = false;
  71. HighscoreSaved = false;
  72. }
  73. /// <summary>
  74. /// Creates a new highscore screen instance.
  75. /// </summary>
  76. public HighScoreScreen()
  77. {
  78. EnabledGestures = GestureType.Tap;
  79. if (HighscoreLoaded == false)
  80. {
  81. throw new InvalidOperationException("Missing highscore data");
  82. }
  83. numberPlaceMapping = new Dictionary<int, string>();
  84. InitializeMapping();
  85. }
  86. /// <summary>
  87. /// Load screen resources
  88. /// </summary>
  89. public override void LoadContent()
  90. {
  91. highScoreFont = Load<SpriteFont>(@"Fonts\HighScoreFont");
  92. safeArea = SafeArea;
  93. base.LoadContent();
  94. }
  95. #endregion
  96. #region Handle Input
  97. /// <summary>
  98. /// Handles user input as a part of screen logic update.
  99. /// </summary>
  100. /// <param name="gameTime">Game time information.</param>
  101. /// <param name="input">Input information.</param>
  102. public override void HandleInput(GameTime gameTime, InputState input)
  103. {
  104. if (input == null)
  105. {
  106. throw new ArgumentNullException("input");
  107. }
  108. if (input.IsPauseGame(null))
  109. {
  110. Exit();
  111. }
  112. // Return to the main menu when a tap gesture is recognized
  113. if (input.Gestures.Count > 0)
  114. {
  115. GestureSample sample = input.Gestures[0];
  116. if (sample.GestureType == GestureType.Tap)
  117. {
  118. Exit();
  119. input.Gestures.Clear();
  120. }
  121. }
  122. // Handle gamepad input
  123. PlayerIndex player;
  124. // Handle keyboard input
  125. if (input.IsNewKeyPress(Keys.Enter, ControllingPlayer, out player) ||
  126. input.IsNewKeyPress(Keys.Space, ControllingPlayer, out player))
  127. {
  128. Exit();
  129. }
  130. }
  131. /// <summary>
  132. /// Exit this screen.
  133. /// </summary>
  134. private void Exit()
  135. {
  136. this.ExitScreen();
  137. ScreenManager.AddScreen(new BackgroundScreen("titlescreen"), null);
  138. ScreenManager.AddScreen(new MainMenuScreen(), null);
  139. }
  140. #endregion
  141. #region Update
  142. /// <summary>
  143. /// Performs update logic.
  144. /// </summary>
  145. /// <param name="gameTime">Game time information.</param>
  146. /// <param name="otherScreenHasFocus">Whether another screen has the focus.</param>
  147. /// <param name="coveredByOtherScreen">Whether this screen is covered by another.</param>
  148. public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen)
  149. {
  150. #if !WINDOWS_PHONE
  151. if (shouldSaveHighScore)
  152. {
  153. SaveHighscore();
  154. }
  155. #endif
  156. base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
  157. }
  158. #endregion
  159. #region Render
  160. /// <summary>
  161. /// Renders the screen.
  162. /// </summary>
  163. /// <param name="gameTime">Game time information</param>
  164. public override void Draw(GameTime gameTime)
  165. {
  166. if (HighscoreLoaded == false)
  167. {
  168. base.Draw(gameTime);
  169. return;
  170. }
  171. ScreenManager.SpriteBatch.Begin();
  172. // Draw the high-scores table
  173. #if WINDOWS_PHONE
  174. for (int i = 0; i < highScore.Count; i++)
  175. {
  176. if (!string.IsNullOrEmpty(highScore[i].Key))
  177. {
  178. // Draw place number
  179. ScreenManager.SpriteBatch.DrawString(highScoreFont, GetPlaceString(i),
  180. new Vector2(safeArea.Left + UIConstants.HighScorePlaceLeftMargin,
  181. safeArea.Top + i * UIConstants.HighScoreVerticalJump + UIConstants.HighScoreTopMargin),
  182. Color.Black);
  183. // Draw Name
  184. ScreenManager.SpriteBatch.DrawString(highScoreFont, highScore[i].Key,
  185. new Vector2(safeArea.Left + UIConstants.HighScoreNameLeftMargin,
  186. safeArea.Top + i * UIConstants.HighScoreVerticalJump + UIConstants.HighScoreTopMargin),
  187. Color.DarkRed);
  188. // Draw score
  189. ScreenManager.SpriteBatch.DrawString(highScoreFont, highScore[i].Value.ToString(),
  190. new Vector2(safeArea.Left + UIConstants.HighScoreScoreLeftMargin,
  191. safeArea.Top + i * UIConstants.HighScoreVerticalJump + UIConstants.HighScoreTopMargin),
  192. Color.Yellow);
  193. }
  194. }
  195. #else
  196. float verticalPosition = UIConstants.HighScoreTopMargin;
  197. for (int i = 0; i < highScore.Count; i++)
  198. {
  199. if (!string.IsNullOrEmpty(highScore[i].Key))
  200. {
  201. // Draw place number
  202. ScreenManager.SpriteBatch.DrawString( highScoreFont, GetPlaceString(i),
  203. new Vector2(safeArea.Left + UIConstants.HighScorePlaceLeftMargin,
  204. safeArea.Top + verticalPosition),
  205. Color.Black);
  206. // Draw Name
  207. ScreenManager.SpriteBatch.DrawString(highScoreFont, highScore[i].Key,
  208. new Vector2(safeArea.Left + UIConstants.HighScoreNameLeftMargin,
  209. safeArea.Top + verticalPosition),
  210. Color.DarkRed);
  211. // Draw score
  212. ScreenManager.SpriteBatch.DrawString(highScoreFont, highScore[i].Value.ToString(),
  213. new Vector2(safeArea.Left + UIConstants.HighScoreScoreLeftMargin,
  214. safeArea.Top + verticalPosition),
  215. Color.Yellow);
  216. }
  217. // Odd and even lines have different height. Remember that "i" is an index so even i's are actually
  218. // odd lines.
  219. if (i % 2 == 0)
  220. {
  221. verticalPosition += UIConstants.HighScoreOddVerticalJump;
  222. }
  223. else
  224. {
  225. verticalPosition += UIConstants.HighScoreEvenVerticalJump;
  226. }
  227. }
  228. #endif
  229. ScreenManager.SpriteBatch.End();
  230. base.Draw(gameTime);
  231. }
  232. #endregion
  233. #region Highscore loading/saving logic
  234. /// <summary>
  235. /// Check if a score belongs on the high score table.
  236. /// </summary>
  237. /// <returns>True if the score belongs on the highscore table, false otherwise.</returns>
  238. public static bool IsInHighscores(int score)
  239. {
  240. // If the score is better than the worst score in the table
  241. return score > highScore[highscorePlaces - 1].Value;
  242. }
  243. /// <summary>
  244. /// Put high score on highscores table.
  245. /// </summary>
  246. /// <param name="name">Player's name.</param>
  247. /// <param name="score">The player's score.</param>
  248. public static void PutHighScore(string playerName, int score)
  249. {
  250. if (IsInHighscores(score))
  251. {
  252. highScore[highscorePlaces - 1] = new KeyValuePair<string, int>(playerName, score);
  253. OrderGameScore();
  254. SaveHighscore();
  255. }
  256. }
  257. /// <summary>
  258. /// Call this method whenever the highscore data changes. This will mark the highscore data as not changed.
  259. /// </summary>
  260. public static void HighScoreChanged()
  261. {
  262. HighscoreSaved = false;
  263. }
  264. /// <summary>
  265. /// Order the high scores table.
  266. /// </summary>
  267. private static void OrderGameScore()
  268. {
  269. highScore.Sort(CompareScores);
  270. }
  271. /// <summary>
  272. /// Comparison method used to compare two highscore entries.
  273. /// </summary>
  274. /// <param name="score1">First highscore entry.</param>
  275. /// <param name="score2">Second highscore entry.</param>
  276. /// <returns>1 if the first highscore is smaller than the second, 0 if both
  277. /// are equal and -1 otherwise.</returns>
  278. private static int CompareScores(KeyValuePair<string, int> score1,
  279. KeyValuePair<string, int> score2)
  280. {
  281. if (score1.Value < score2.Value)
  282. {
  283. return 1;
  284. }
  285. if (score1.Value == score2.Value)
  286. {
  287. return 0;
  288. }
  289. return -1;
  290. }
  291. #if !WINDOWS_PHONE
  292. /// <summary>
  293. /// Initializes the screen's storage device.
  294. /// </summary>
  295. public static void InitializeStorageDevice()
  296. {
  297. if (Storage == null && Guide.IsVisible == false && deviceSelectorLaunched == false)
  298. {
  299. deviceSelectorLaunched = true;
  300. StorageDevice.BeginShowSelector(PlayerIndex.One, GetDevice, null);
  301. }
  302. }
  303. /// <summary>
  304. /// Handler for asynchronous storage device result.
  305. /// </summary>
  306. /// <param name="result">Result of the call for storage device selection/initialization.</param>
  307. static void GetDevice(IAsyncResult result)
  308. {
  309. Storage = StorageDevice.EndShowSelector(result);
  310. deviceSelectorLaunched = false;
  311. }
  312. #endif
  313. /// <summary>
  314. /// Saves the current highscore to a text file.
  315. /// </summary>
  316. public static void SaveHighscore()
  317. {
  318. #if WINDOWS_PHONE
  319. // Get the place to store the data
  320. using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
  321. {
  322. // Create the file to save the data
  323. using (IsolatedStorageFileStream isfs = isf.CreateFile(HighScoreScreen.HighScoreFilename))
  324. {
  325. using (StreamWriter writer = new StreamWriter(isfs))
  326. {
  327. for (int i = 0; i < highScore.Count; i++)
  328. {
  329. // Write the scores
  330. writer.WriteLine(highScore[i].Key);
  331. writer.WriteLine(highScore[i].Value.ToString());
  332. }
  333. }
  334. }
  335. }
  336. HighscoreSaved = true;
  337. #else
  338. if (Storage == null || Storage.IsConnected == false)
  339. {
  340. shouldSaveHighScore = true;
  341. // We do not have a storage device, initialize it
  342. InitializeStorageDevice();
  343. }
  344. else if (!savingHighscore)
  345. {
  346. shouldSaveHighScore = false;
  347. savingHighscore = true;
  348. SaveHighscoreToStorage();
  349. }
  350. #endif
  351. }
  352. #if !WINDOWS_PHONE
  353. /// <summary>
  354. /// Saves the high score data to the initialized storage device.
  355. /// </summary>
  356. private static void SaveHighscoreToStorage()
  357. {
  358. Storage.BeginOpenContainer(HoneycombRush.GameName, SaveContainerOpened, null);
  359. }
  360. /// <summary>
  361. /// Handler for initializing the storage container.
  362. /// </summary>
  363. /// <param name="result">Asynchronous result of the storage container initialization.</param>
  364. private static void SaveContainerOpened(IAsyncResult result)
  365. {
  366. StorageContainer container = Storage.EndOpenContainer(result);
  367. if (container.FileExists(HighScoreFilename))
  368. {
  369. container.DeleteFile(HighScoreFilename);
  370. }
  371. Stream stream = container.CreateFile(HighScoreFilename);
  372. using (StreamWriter writer = new StreamWriter(stream))
  373. {
  374. for (int i = 0; i < highScore.Count; i++)
  375. {
  376. // Write the scores
  377. writer.WriteLine(highScore[i].Key);
  378. writer.WriteLine(highScore[i].Value.ToString());
  379. }
  380. }
  381. HighscoreSaved = true;
  382. savingHighscore = false;
  383. }
  384. #endif
  385. /// <summary>
  386. /// Loads the high score from a text file.
  387. /// </summary>
  388. public static void LoadHighscores()
  389. {
  390. #if WINDOWS_PHONE
  391. // Get the place the data stored
  392. using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
  393. {
  394. // Try to open the file
  395. if (isf.FileExists(HighScoreScreen.HighScoreFilename))
  396. {
  397. using (IsolatedStorageFileStream isfs =
  398. isf.OpenFile(HighScoreScreen.HighScoreFilename, FileMode.Open))
  399. {
  400. // Get the stream to read the data
  401. using (StreamReader reader = new StreamReader(isfs))
  402. {
  403. // Read the highscores
  404. int i = 0;
  405. while (!reader.EndOfStream)
  406. {
  407. string name = reader.ReadLine();
  408. string score = reader.ReadLine();
  409. highScore[i++] = new KeyValuePair<string, int>(name, int.Parse(score));
  410. }
  411. }
  412. }
  413. }
  414. }
  415. OrderGameScore();
  416. HighscoreLoaded = true;
  417. #else
  418. if (Storage == null || Storage.IsConnected == false)
  419. {
  420. // We do not have a storage device, initialize it
  421. InitializeStorageDevice();
  422. }
  423. else if (!loadingHighscore)
  424. {
  425. loadingHighscore = true;
  426. LoadHighscoreFromStorage();
  427. }
  428. #endif
  429. }
  430. #if !WINDOWS_PHONE
  431. /// <summary>
  432. /// Handler for initializing the storage container.
  433. /// </summary>
  434. /// <param name="result">Asynchronous result of the storage container initialization.</param>
  435. public static void LoadHighscoreFromStorage()
  436. {
  437. Storage.BeginOpenContainer(HoneycombRush.GameName, LoadContainerOpened, null);
  438. }
  439. /// <summary>
  440. /// Handler for initializing the storage container.
  441. /// </summary>
  442. /// <param name="result">Asynchronous result of the storage container initialization.</param>
  443. public static void LoadContainerOpened(IAsyncResult result)
  444. {
  445. StorageContainer container = Storage.EndOpenContainer(result);
  446. if (container.FileExists(HighScoreFilename))
  447. {
  448. Stream stream = container.OpenFile(HighScoreFilename, FileMode.Open);
  449. using (StreamReader reader = new StreamReader(stream))
  450. {
  451. // Read the highscores
  452. int i = 0;
  453. while (!reader.EndOfStream)
  454. {
  455. string name = reader.ReadLine();
  456. string score = reader.ReadLine();
  457. highScore[i++] = new KeyValuePair<string, int>(name, int.Parse(score));
  458. }
  459. }
  460. }
  461. OrderGameScore();
  462. HighscoreLoaded = true;
  463. loadingHighscore = false;
  464. }
  465. #endif
  466. /// <summary>
  467. /// Gets a string describing an index's position in the highscore.
  468. /// </summary>
  469. /// <param name="number">Score's index.</param>
  470. /// <returns>A string describing the score's index.</returns>
  471. private string GetPlaceString(int number)
  472. {
  473. return numberPlaceMapping[number];
  474. }
  475. /// <summary>
  476. /// Initializes the mapping between score indices and position strings.
  477. /// </summary>
  478. private void InitializeMapping()
  479. {
  480. numberPlaceMapping.Add(0, "1ST");
  481. numberPlaceMapping.Add(1, "2ND");
  482. numberPlaceMapping.Add(2, "3RD");
  483. numberPlaceMapping.Add(3, "4TH");
  484. numberPlaceMapping.Add(4, "5TH");
  485. numberPlaceMapping.Add(5, "6TH");
  486. numberPlaceMapping.Add(6, "7TH");
  487. }
  488. #endregion
  489. }
  490. }