PlatformerGame.cs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // PlatformerGame.cs
  4. //
  5. // Microsoft XNA Community Game Platform
  6. // Copyright (C) Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #endregion
  9. using System;
  10. using System.IO;
  11. #if ANDROID
  12. using Android.App;
  13. #endif
  14. using Microsoft.Xna.Framework;
  15. using Microsoft.Xna.Framework.Graphics;
  16. using Microsoft.Xna.Framework.Input;
  17. using Microsoft.Xna.Framework.Media;
  18. using Microsoft.Xna.Framework.Input.Touch;
  19. namespace Platformer
  20. {
  21. /// <summary>
  22. /// This is the main type for your game
  23. /// </summary>
  24. public class PlatformerGame : Microsoft.Xna.Framework.Game
  25. {
  26. // Resources for drawing.
  27. private GraphicsDeviceManager graphics;
  28. private SpriteBatch spriteBatch;
  29. // Global content.
  30. private SpriteFont hudFont;
  31. private Texture2D winOverlay;
  32. private Texture2D loseOverlay;
  33. private Texture2D diedOverlay;
  34. // Meta-level game state.
  35. private int levelIndex = -1;
  36. private Level level;
  37. private bool wasContinuePressed;
  38. // When the time remaining is less than the warning time, it blinks on the hud
  39. private static readonly TimeSpan WarningTime = TimeSpan.FromSeconds(30);
  40. // We store our input states so that we only poll once per frame,
  41. // then we use the same input state wherever needed
  42. private GamePadState gamePadState;
  43. private KeyboardState keyboardState;
  44. private TouchCollection touchState;
  45. private AccelerometerState accelerometerState;
  46. // The number of levels in the Levels directory of our content. We assume that
  47. // levels in our content are 0-based and that all numbers under this constant
  48. // have a level file present. This allows us to not need to check for the file
  49. // or handle exceptions, both of which can add unnecessary time to level loading.
  50. private const int numberOfLevels = 3;
  51. public PlatformerGame()
  52. {
  53. graphics = new GraphicsDeviceManager(this);
  54. Content.RootDirectory = "Content";
  55. #if WINDOWS_PHONE || ANDROID
  56. TargetElapsedTime = TimeSpan.FromTicks(333333);
  57. #endif
  58. #if MONOMAC
  59. graphics.PreferredBackBufferWidth = 800;
  60. graphics.PreferredBackBufferHeight = 480;
  61. #else
  62. graphics.IsFullScreen = true;
  63. graphics.SupportedOrientations = DisplayOrientation.LandscapeLeft | DisplayOrientation.LandscapeRight;
  64. #endif
  65. Accelerometer.Initialize();
  66. }
  67. /// <summary>
  68. /// LoadContent will be called once per game and is the place to load
  69. /// all of your content.
  70. /// </summary>
  71. protected override void LoadContent()
  72. {
  73. // Create a new SpriteBatch, which can be used to draw textures.
  74. spriteBatch = new SpriteBatch(GraphicsDevice);
  75. // Load fonts
  76. hudFont = Content.Load<SpriteFont>("Fonts/Hud");
  77. // Load overlay textures
  78. winOverlay = Content.Load<Texture2D>("Overlays/you_win");
  79. loseOverlay = Content.Load<Texture2D>("Overlays/you_lose");
  80. diedOverlay = Content.Load<Texture2D>("Overlays/you_died");
  81. //Known issue that you get exceptions if you use Media PLayer while connected to your PC
  82. //See http://social.msdn.microsoft.com/Forums/en/windowsphone7series/thread/c8a243d2-d360-46b1-96bd-62b1ef268c66
  83. //Which means its impossible to test this from VS.
  84. //So we have to catch the exception and throw it away
  85. try
  86. {
  87. MediaPlayer.IsRepeating = true;
  88. MediaPlayer.Play(Content.Load<Song>("Sounds/Music"));
  89. }
  90. catch { }
  91. LoadNextLevel();
  92. }
  93. /// <summary>
  94. /// Allows the game to run logic such as updating the world,
  95. /// checking for collisions, gathering input, and playing audio.
  96. /// </summary>
  97. /// <param name="gameTime">Provides a snapshot of timing values.</param>
  98. protected override void Update(GameTime gameTime)
  99. {
  100. // Handle polling for our input and handling high-level input
  101. HandleInput();
  102. // update our level, passing down the GameTime along with all of our input states
  103. level.Update(gameTime, keyboardState, gamePadState, touchState,
  104. accelerometerState, Window.CurrentOrientation);
  105. base.Update(gameTime);
  106. }
  107. private void HandleInput()
  108. {
  109. // get all of our input states
  110. keyboardState = Keyboard.GetState();
  111. gamePadState = GamePad.GetState(PlayerIndex.One);
  112. touchState = TouchPanel.GetState();
  113. accelerometerState = Accelerometer.GetState();
  114. // Exit the game when back is pressed.
  115. if (gamePadState.Buttons.Back == ButtonState.Pressed)
  116. Exit();
  117. bool continuePressed =
  118. keyboardState.IsKeyDown(Keys.Space) ||
  119. gamePadState.IsButtonDown(Buttons.A) ||
  120. touchState.AnyTouch();
  121. // Perform the appropriate action to advance the game and
  122. // to get the player back to playing.
  123. if (!wasContinuePressed && continuePressed)
  124. {
  125. if (!level.Player.IsAlive)
  126. {
  127. level.StartNewLife();
  128. }
  129. else if (level.TimeRemaining == TimeSpan.Zero)
  130. {
  131. if (level.ReachedExit)
  132. LoadNextLevel();
  133. else
  134. ReloadCurrentLevel();
  135. }
  136. }
  137. wasContinuePressed = continuePressed;
  138. }
  139. private void LoadNextLevel()
  140. {
  141. // move to the next level
  142. levelIndex = (levelIndex + 1) % numberOfLevels;
  143. // Unloads the content for the current level before loading the next one.
  144. if (level != null)
  145. level.Dispose();
  146. // Load the level.
  147. string levelPath = string.Format("{0}/Levels/{1}.txt", Content.RootDirectory, levelIndex);
  148. using (Stream fileStream = TitleContainer.OpenStream(levelPath))
  149. level = new Level(Services, fileStream, levelIndex);
  150. }
  151. private void ReloadCurrentLevel()
  152. {
  153. --levelIndex;
  154. LoadNextLevel();
  155. }
  156. /// <summary>
  157. /// Draws the game from background to foreground.
  158. /// </summary>
  159. /// <param name="gameTime">Provides a snapshot of timing values.</param>
  160. protected override void Draw(GameTime gameTime)
  161. {
  162. graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
  163. spriteBatch.Begin();
  164. level.Draw(gameTime, spriteBatch);
  165. DrawHud();
  166. GamePad.Draw(gameTime, spriteBatch);
  167. spriteBatch.End();
  168. base.Draw(gameTime);
  169. }
  170. private void DrawHud()
  171. {
  172. Rectangle titleSafeArea = GraphicsDevice.Viewport.TitleSafeArea;
  173. Vector2 hudLocation = new Vector2(titleSafeArea.X, titleSafeArea.Y);
  174. Vector2 center = new Vector2(titleSafeArea.X + titleSafeArea.Width / 2.0f,
  175. titleSafeArea.Y + titleSafeArea.Height / 2.0f);
  176. // Draw time remaining. Uses modulo division to cause blinking when the
  177. // player is running out of time.
  178. string timeString = "TIME: " + level.TimeRemaining.Minutes.ToString("00") + ":" + level.TimeRemaining.Seconds.ToString("00");
  179. Color timeColor;
  180. if (level.TimeRemaining > WarningTime ||
  181. level.ReachedExit ||
  182. (int)level.TimeRemaining.TotalSeconds % 2 == 0)
  183. {
  184. timeColor = Color.Yellow;
  185. }
  186. else
  187. {
  188. timeColor = Color.Red;
  189. }
  190. DrawShadowedString(hudFont, timeString, hudLocation, timeColor);
  191. // Draw score
  192. float timeHeight = hudFont.MeasureString(timeString).Y;
  193. DrawShadowedString(hudFont, "SCORE: " + level.Score.ToString(), hudLocation + new Vector2(0.0f, timeHeight * 1.2f), Color.Yellow);
  194. // Determine the status overlay message to show.
  195. Texture2D status = null;
  196. if (level.TimeRemaining == TimeSpan.Zero)
  197. {
  198. if (level.ReachedExit)
  199. {
  200. status = winOverlay;
  201. }
  202. else
  203. {
  204. status = loseOverlay;
  205. }
  206. }
  207. else if (!level.Player.IsAlive)
  208. {
  209. status = diedOverlay;
  210. }
  211. if (status != null)
  212. {
  213. // Draw status message.
  214. Vector2 statusSize = new Vector2(status.Width, status.Height);
  215. spriteBatch.Draw(status, center - statusSize / 2, Color.White);
  216. }
  217. }
  218. private void DrawShadowedString(SpriteFont font, string value, Vector2 position, Color color)
  219. {
  220. spriteBatch.DrawString(font, value, position + new Vector2(1.0f, 1.0f), Color.Black);
  221. spriteBatch.DrawString(font, value, position, color);
  222. }
  223. }
  224. }