HighScoreScreen.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  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. input.IsNewMouseClick(InputState.MouseButton.Left, ControllingPlayer, out player))
  128. {
  129. Exit();
  130. }
  131. }
  132. /// <summary>
  133. /// Exit this screen.
  134. /// </summary>
  135. private void Exit()
  136. {
  137. this.ExitScreen();
  138. ScreenManager.AddScreen(new BackgroundScreen("titlescreen"), null);
  139. ScreenManager.AddScreen(new MainMenuScreen(), null);
  140. }
  141. #endregion
  142. #region Update
  143. /// <summary>
  144. /// Performs update logic.
  145. /// </summary>
  146. /// <param name="gameTime">Game time information.</param>
  147. /// <param name="otherScreenHasFocus">Whether another screen has the focus.</param>
  148. /// <param name="coveredByOtherScreen">Whether this screen is covered by another.</param>
  149. public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen)
  150. {
  151. #if !WINDOWS_PHONE
  152. if (shouldSaveHighScore)
  153. {
  154. SaveHighscore();
  155. }
  156. #endif
  157. base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
  158. }
  159. #endregion
  160. #region Render
  161. /// <summary>
  162. /// Renders the screen.
  163. /// </summary>
  164. /// <param name="gameTime">Game time information</param>
  165. public override void Draw(GameTime gameTime)
  166. {
  167. if (HighscoreLoaded == false)
  168. {
  169. base.Draw(gameTime);
  170. return;
  171. }
  172. ScreenManager.SpriteBatch.Begin();
  173. // Draw the high-scores table
  174. #if WINDOWS_PHONE
  175. for (int i = 0; i < highScore.Count; i++)
  176. {
  177. if (!string.IsNullOrEmpty(highScore[i].Key))
  178. {
  179. // Draw place number
  180. ScreenManager.SpriteBatch.DrawString(highScoreFont, GetPlaceString(i),
  181. new Vector2(safeArea.Left + UIConstants.HighScorePlaceLeftMargin,
  182. safeArea.Top + i * UIConstants.HighScoreVerticalJump + UIConstants.HighScoreTopMargin),
  183. Color.Black);
  184. // Draw Name
  185. ScreenManager.SpriteBatch.DrawString(highScoreFont, highScore[i].Key,
  186. new Vector2(safeArea.Left + UIConstants.HighScoreNameLeftMargin,
  187. safeArea.Top + i * UIConstants.HighScoreVerticalJump + UIConstants.HighScoreTopMargin),
  188. Color.DarkRed);
  189. // Draw score
  190. ScreenManager.SpriteBatch.DrawString(highScoreFont, highScore[i].Value.ToString(),
  191. new Vector2(safeArea.Left + UIConstants.HighScoreScoreLeftMargin,
  192. safeArea.Top + i * UIConstants.HighScoreVerticalJump + UIConstants.HighScoreTopMargin),
  193. Color.Yellow);
  194. }
  195. }
  196. #else
  197. float verticalPosition = UIConstants.HighScoreTopMargin;
  198. for (int i = 0; i < highScore.Count; i++)
  199. {
  200. if (!string.IsNullOrEmpty(highScore[i].Key))
  201. {
  202. // Draw place number
  203. ScreenManager.SpriteBatch.DrawString( highScoreFont, GetPlaceString(i),
  204. new Vector2(safeArea.Left + UIConstants.HighScorePlaceLeftMargin,
  205. safeArea.Top + verticalPosition),
  206. Color.Black);
  207. // Draw Name
  208. ScreenManager.SpriteBatch.DrawString(highScoreFont, highScore[i].Key,
  209. new Vector2(safeArea.Left + UIConstants.HighScoreNameLeftMargin,
  210. safeArea.Top + verticalPosition),
  211. Color.DarkRed);
  212. // Draw score
  213. ScreenManager.SpriteBatch.DrawString(highScoreFont, highScore[i].Value.ToString(),
  214. new Vector2(safeArea.Left + UIConstants.HighScoreScoreLeftMargin,
  215. safeArea.Top + verticalPosition),
  216. Color.Yellow);
  217. }
  218. // Odd and even lines have different height. Remember that "i" is an index so even i's are actually
  219. // odd lines.
  220. if (i % 2 == 0)
  221. {
  222. verticalPosition += UIConstants.HighScoreOddVerticalJump;
  223. }
  224. else
  225. {
  226. verticalPosition += UIConstants.HighScoreEvenVerticalJump;
  227. }
  228. }
  229. #endif
  230. ScreenManager.SpriteBatch.End();
  231. base.Draw(gameTime);
  232. }
  233. #endregion
  234. #region Highscore loading/saving logic
  235. /// <summary>
  236. /// Check if a score belongs on the high score table.
  237. /// </summary>
  238. /// <returns>True if the score belongs on the highscore table, false otherwise.</returns>
  239. public static bool IsInHighscores(int score)
  240. {
  241. // If the score is better than the worst score in the table
  242. return score > highScore[highscorePlaces - 1].Value;
  243. }
  244. /// <summary>
  245. /// Put high score on highscores table.
  246. /// </summary>
  247. /// <param name="name">Player's name.</param>
  248. /// <param name="score">The player's score.</param>
  249. public static void PutHighScore(string playerName, int score)
  250. {
  251. if (IsInHighscores(score))
  252. {
  253. highScore[highscorePlaces - 1] = new KeyValuePair<string, int>(playerName, score);
  254. OrderGameScore();
  255. SaveHighscore();
  256. }
  257. }
  258. /// <summary>
  259. /// Call this method whenever the highscore data changes. This will mark the highscore data as not changed.
  260. /// </summary>
  261. public static void HighScoreChanged()
  262. {
  263. HighscoreSaved = false;
  264. }
  265. /// <summary>
  266. /// Order the high scores table.
  267. /// </summary>
  268. private static void OrderGameScore()
  269. {
  270. highScore.Sort(CompareScores);
  271. }
  272. /// <summary>
  273. /// Comparison method used to compare two highscore entries.
  274. /// </summary>
  275. /// <param name="score1">First highscore entry.</param>
  276. /// <param name="score2">Second highscore entry.</param>
  277. /// <returns>1 if the first highscore is smaller than the second, 0 if both
  278. /// are equal and -1 otherwise.</returns>
  279. private static int CompareScores(KeyValuePair<string, int> score1,
  280. KeyValuePair<string, int> score2)
  281. {
  282. if (score1.Value < score2.Value)
  283. {
  284. return 1;
  285. }
  286. if (score1.Value == score2.Value)
  287. {
  288. return 0;
  289. }
  290. return -1;
  291. }
  292. #if !WINDOWS_PHONE
  293. /// <summary>
  294. /// Initializes the screen's storage device.
  295. /// </summary>
  296. public static void InitializeStorageDevice()
  297. {
  298. if (Storage == null && Guide.IsVisible == false && deviceSelectorLaunched == false)
  299. {
  300. deviceSelectorLaunched = true;
  301. StorageDevice.BeginShowSelector(PlayerIndex.One, GetDevice, null);
  302. }
  303. }
  304. /// <summary>
  305. /// Handler for asynchronous storage device result.
  306. /// </summary>
  307. /// <param name="result">Result of the call for storage device selection/initialization.</param>
  308. static void GetDevice(IAsyncResult result)
  309. {
  310. Storage = StorageDevice.EndShowSelector(result);
  311. deviceSelectorLaunched = false;
  312. }
  313. #endif
  314. /// <summary>
  315. /// Saves the current highscore to a text file.
  316. /// </summary>
  317. public static void SaveHighscore()
  318. {
  319. #if WINDOWS_PHONE
  320. // Get the place to store the data
  321. using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
  322. {
  323. // Create the file to save the data
  324. using (IsolatedStorageFileStream isfs = isf.CreateFile(HighScoreScreen.HighScoreFilename))
  325. {
  326. using (StreamWriter writer = new StreamWriter(isfs))
  327. {
  328. for (int i = 0; i < highScore.Count; i++)
  329. {
  330. // Write the scores
  331. writer.WriteLine(highScore[i].Key);
  332. writer.WriteLine(highScore[i].Value.ToString());
  333. }
  334. }
  335. }
  336. }
  337. HighscoreSaved = true;
  338. #else
  339. if (Storage == null || Storage.IsConnected == false)
  340. {
  341. shouldSaveHighScore = true;
  342. // We do not have a storage device, initialize it
  343. InitializeStorageDevice();
  344. }
  345. else if (!savingHighscore)
  346. {
  347. shouldSaveHighScore = false;
  348. savingHighscore = true;
  349. SaveHighscoreToStorage();
  350. }
  351. #endif
  352. }
  353. #if !WINDOWS_PHONE
  354. /// <summary>
  355. /// Saves the high score data to the initialized storage device.
  356. /// </summary>
  357. private static void SaveHighscoreToStorage()
  358. {
  359. Storage.BeginOpenContainer(HoneycombRush.GameName, SaveContainerOpened, null);
  360. }
  361. /// <summary>
  362. /// Handler for initializing the storage container.
  363. /// </summary>
  364. /// <param name="result">Asynchronous result of the storage container initialization.</param>
  365. private static void SaveContainerOpened(IAsyncResult result)
  366. {
  367. StorageContainer container = Storage.EndOpenContainer(result);
  368. if (container.FileExists(HighScoreFilename))
  369. {
  370. container.DeleteFile(HighScoreFilename);
  371. }
  372. Stream stream = container.CreateFile(HighScoreFilename);
  373. using (StreamWriter writer = new StreamWriter(stream))
  374. {
  375. for (int i = 0; i < highScore.Count; i++)
  376. {
  377. // Write the scores
  378. writer.WriteLine(highScore[i].Key);
  379. writer.WriteLine(highScore[i].Value.ToString());
  380. }
  381. }
  382. HighscoreSaved = true;
  383. savingHighscore = false;
  384. }
  385. #endif
  386. /// <summary>
  387. /// Loads the high score from a text file.
  388. /// </summary>
  389. public static void LoadHighscores()
  390. {
  391. #if WINDOWS_PHONE
  392. // Get the place the data stored
  393. using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
  394. {
  395. // Try to open the file
  396. if (isf.FileExists(HighScoreScreen.HighScoreFilename))
  397. {
  398. using (IsolatedStorageFileStream isfs =
  399. isf.OpenFile(HighScoreScreen.HighScoreFilename, FileMode.Open))
  400. {
  401. // Get the stream to read the data
  402. using (StreamReader reader = new StreamReader(isfs))
  403. {
  404. // Read the highscores
  405. int i = 0;
  406. while (!reader.EndOfStream)
  407. {
  408. string name = reader.ReadLine();
  409. string score = reader.ReadLine();
  410. highScore[i++] = new KeyValuePair<string, int>(name, int.Parse(score));
  411. }
  412. }
  413. }
  414. }
  415. }
  416. OrderGameScore();
  417. HighscoreLoaded = true;
  418. #else
  419. if (Storage == null || Storage.IsConnected == false)
  420. {
  421. // We do not have a storage device, initialize it
  422. InitializeStorageDevice();
  423. }
  424. else if (!loadingHighscore)
  425. {
  426. loadingHighscore = true;
  427. LoadHighscoreFromStorage();
  428. }
  429. #endif
  430. }
  431. #if !WINDOWS_PHONE
  432. /// <summary>
  433. /// Handler for initializing the storage container.
  434. /// </summary>
  435. /// <param name="result">Asynchronous result of the storage container initialization.</param>
  436. public static void LoadHighscoreFromStorage()
  437. {
  438. Storage.BeginOpenContainer(HoneycombRush.GameName, LoadContainerOpened, null);
  439. }
  440. /// <summary>
  441. /// Handler for initializing the storage container.
  442. /// </summary>
  443. /// <param name="result">Asynchronous result of the storage container initialization.</param>
  444. public static void LoadContainerOpened(IAsyncResult result)
  445. {
  446. StorageContainer container = Storage.EndOpenContainer(result);
  447. if (container.FileExists(HighScoreFilename))
  448. {
  449. Stream stream = container.OpenFile(HighScoreFilename, FileMode.Open);
  450. using (StreamReader reader = new StreamReader(stream))
  451. {
  452. // Read the highscores
  453. int i = 0;
  454. while (!reader.EndOfStream)
  455. {
  456. string name = reader.ReadLine();
  457. string score = reader.ReadLine();
  458. highScore[i++] = new KeyValuePair<string, int>(name, int.Parse(score));
  459. }
  460. }
  461. }
  462. OrderGameScore();
  463. HighscoreLoaded = true;
  464. loadingHighscore = false;
  465. }
  466. #endif
  467. /// <summary>
  468. /// Gets a string describing an index's position in the highscore.
  469. /// </summary>
  470. /// <param name="number">Score's index.</param>
  471. /// <returns>A string describing the score's index.</returns>
  472. private string GetPlaceString(int number)
  473. {
  474. return numberPlaceMapping[number];
  475. }
  476. /// <summary>
  477. /// Initializes the mapping between score indices and position strings.
  478. /// </summary>
  479. private void InitializeMapping()
  480. {
  481. numberPlaceMapping.Add(0, "1ST");
  482. numberPlaceMapping.Add(1, "2ND");
  483. numberPlaceMapping.Add(2, "3RD");
  484. numberPlaceMapping.Add(3, "4TH");
  485. numberPlaceMapping.Add(4, "5TH");
  486. numberPlaceMapping.Add(5, "6TH");
  487. numberPlaceMapping.Add(6, "7TH");
  488. }
  489. #endregion
  490. }
  491. }