GameplayScreen.cs 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. //-----------------------------------------------------------------------------
  2. // GameplayScreen.cs
  3. //
  4. // Microsoft XNA Community Game Platform
  5. // Copyright (C) Microsoft Corporation. All rights reserved.
  6. //-----------------------------------------------------------------------------
  7. using System;
  8. using System.Threading;
  9. using Microsoft.Xna.Framework;
  10. using Microsoft.Xna.Framework.Content;
  11. using Microsoft.Xna.Framework.Graphics;
  12. using Microsoft.Xna.Framework.Input;
  13. using Microsoft.Xna.Framework.Net;
  14. namespace NetworkStateManagement
  15. {
  16. /// <summary>
  17. /// This screen implements the actual game logic. It is just a
  18. /// placeholder to get the idea across: you'll probably want to
  19. /// put some more interesting gameplay in here!
  20. /// </summary>
  21. class GameplayScreen : GameScreen
  22. {
  23. NetworkSession networkSession;
  24. ContentManager content;
  25. SpriteFont gameFont;
  26. Vector2 playerPosition = new Vector2(100, 100);
  27. Vector2 enemyPosition = new Vector2(100, 100);
  28. Random random = new Random();
  29. float pauseAlpha;
  30. /// <summary>
  31. /// The logic for deciding whether the game is paused depends on whether
  32. /// this is a networked or single player game. If we are in a network session,
  33. /// we should go on updating the game even when the user tabs away from us or
  34. /// brings up the pause menu, because even though the local player is not
  35. /// responding to input, other remote players may not be paused. In single
  36. /// player modes, however, we want everything to pause if the game loses focus.
  37. /// </summary>
  38. new bool IsActive
  39. {
  40. get
  41. {
  42. if (networkSession == null)
  43. {
  44. // Pause behavior for single player games.
  45. return base.IsActive;
  46. }
  47. else
  48. {
  49. // Pause behavior for networked games.
  50. return !IsExiting;
  51. }
  52. }
  53. }
  54. /// <summary>
  55. /// Constructor.
  56. /// </summary>
  57. public GameplayScreen(NetworkSession networkSession)
  58. {
  59. this.networkSession = networkSession;
  60. TransitionOnTime = TimeSpan.FromSeconds(1.5);
  61. TransitionOffTime = TimeSpan.FromSeconds(0.5);
  62. }
  63. /// <summary>
  64. /// Load graphics content for the game.
  65. /// </summary>
  66. public override void LoadContent()
  67. {
  68. if (content == null)
  69. content = new ContentManager(ScreenManager.Game.Services, "Content");
  70. gameFont = content.Load<SpriteFont>("gamefont");
  71. // A real game would probably have more content than this sample, so
  72. // it would take longer to load. We simulate that by delaying for a
  73. // while, giving you a chance to admire the beautiful loading screen.
  74. Thread.Sleep(1000);
  75. // once the load has finished, we use ResetElapsedTime to tell the game's
  76. // timing mechanism that we have just finished a very long frame, and that
  77. // it should not try to catch up.
  78. ScreenManager.Game.ResetElapsedTime();
  79. }
  80. /// <summary>
  81. /// Unload graphics content used by the game.
  82. /// </summary>
  83. public override void UnloadContent()
  84. {
  85. content.Unload();
  86. }
  87. /// <summary>
  88. /// Updates the state of the game.
  89. /// </summary>
  90. public override void Update(GameTime gameTime, bool otherScreenHasFocus,
  91. bool coveredByOtherScreen)
  92. {
  93. base.Update(gameTime, otherScreenHasFocus, false);
  94. // Gradually fade in or out depending on whether we are covered by the pause screen.
  95. if (coveredByOtherScreen)
  96. pauseAlpha = Math.Min(pauseAlpha + 1f / 32, 1);
  97. else
  98. pauseAlpha = Math.Max(pauseAlpha - 1f / 32, 0);
  99. if (IsActive)
  100. {
  101. // Apply some random jitter to make the enemy move around.
  102. const float randomization = 10;
  103. enemyPosition.X += (float)(random.NextDouble() - 0.5) * randomization;
  104. enemyPosition.Y += (float)(random.NextDouble() - 0.5) * randomization;
  105. // Apply a stabilizing force to stop the enemy moving off the screen.
  106. Vector2 targetPosition = new Vector2(200, 200);
  107. enemyPosition = Vector2.Lerp(enemyPosition, targetPosition, 0.05f);
  108. // TODO: this game isn't very fun! You could probably improve
  109. // it by inserting something more interesting in this space :-)
  110. }
  111. // If we are in a network game, check if we should return to the lobby.
  112. if ((networkSession != null) && !IsExiting)
  113. {
  114. if (networkSession.SessionState == NetworkSessionState.Lobby)
  115. {
  116. LoadingScreen.Load(ScreenManager, true, null,
  117. new BackgroundScreen(),
  118. new LobbyScreen(networkSession));
  119. }
  120. }
  121. }
  122. /// <summary>
  123. /// Lets the game respond to player input. Unlike the Update method,
  124. /// this will only be called when the gameplay screen is active.
  125. /// </summary>
  126. public override void HandleInput(InputState input)
  127. {
  128. if (input == null)
  129. throw new ArgumentNullException("input");
  130. if (ControllingPlayer.HasValue)
  131. {
  132. // In single player games, handle input for the controlling player.
  133. HandlePlayerInput(input, ControllingPlayer.Value);
  134. }
  135. else if (networkSession != null)
  136. {
  137. // In network game modes, handle input for all the
  138. // local players who are participating in the session.
  139. foreach (NetworkGamer gamer in networkSession.LocalGamers)
  140. {
  141. // TODO: Cast to LocalNetworkGamer if needed, or check if gamer is local
  142. var localGamer = gamer as LocalNetworkGamer ?? (LocalNetworkGamer)gamer;
  143. if (!HandlePlayerInput(input, (PlayerIndex)localGamer.SignedInGamer.PlayerIndex))
  144. break;
  145. }
  146. }
  147. }
  148. /// <summary>
  149. /// Handles input for the specified player. In local game modes, this is called
  150. /// just once for the controlling player. In network modes, it can be called
  151. /// more than once if there are multiple profiles playing on the local machine.
  152. /// Returns true if we should continue to handle input for subsequent players,
  153. /// or false if this player has paused the game.
  154. /// </summary>
  155. bool HandlePlayerInput(InputState input, PlayerIndex playerIndex)
  156. {
  157. // Look up inputs for the specified player profile.
  158. KeyboardState keyboardState = input.CurrentKeyboardStates[(int)playerIndex];
  159. GamePadState gamePadState = input.CurrentGamePadStates[(int)playerIndex];
  160. // The game pauses either if the user presses the pause button, or if
  161. // they unplug the active gamepad. This requires us to keep track of
  162. // whether a gamepad was ever plugged in, because we don't want to pause
  163. // on PC if they are playing with a keyboard and have no gamepad at all!
  164. bool gamePadDisconnected = !gamePadState.IsConnected &&
  165. input.GamePadWasConnected[(int)playerIndex];
  166. if (input.IsPauseGame(playerIndex) || gamePadDisconnected)
  167. {
  168. ScreenManager.AddScreen(new PauseMenuScreen(networkSession), playerIndex);
  169. return false;
  170. }
  171. // Otherwise move the player position.
  172. Vector2 movement = Vector2.Zero;
  173. if (keyboardState.IsKeyDown(Keys.Left))
  174. movement.X--;
  175. if (keyboardState.IsKeyDown(Keys.Right))
  176. movement.X++;
  177. if (keyboardState.IsKeyDown(Keys.Up))
  178. movement.Y--;
  179. if (keyboardState.IsKeyDown(Keys.Down))
  180. movement.Y++;
  181. Vector2 thumbstick = gamePadState.ThumbSticks.Left;
  182. movement.X += thumbstick.X;
  183. movement.Y -= thumbstick.Y;
  184. if (movement.Length() > 1)
  185. movement.Normalize();
  186. playerPosition += movement * 2;
  187. return true;
  188. }
  189. /// <summary>
  190. /// Draws the gameplay screen.
  191. /// </summary>
  192. public override void Draw(GameTime gameTime)
  193. {
  194. // This game has a blue background. Why? Because!
  195. ScreenManager.GraphicsDevice.Clear(ClearOptions.Target,
  196. Color.CornflowerBlue, 0, 0);
  197. // Our player and enemy are both actually just text strings.
  198. SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
  199. spriteBatch.Begin();
  200. spriteBatch.DrawString(gameFont, "// TODO", playerPosition, Color.Green);
  201. spriteBatch.DrawString(gameFont, "Insert Gameplay Here",
  202. enemyPosition, Color.DarkRed);
  203. if (networkSession != null)
  204. {
  205. string message = "Players: " + networkSession.AllGamers.Count;
  206. Vector2 messagePosition = new Vector2(100, 480);
  207. spriteBatch.DrawString(gameFont, message, messagePosition, Color.White);
  208. }
  209. spriteBatch.End();
  210. // If the game is transitioning on or off, fade it out to black.
  211. if (TransitionPosition > 0 || pauseAlpha > 0)
  212. {
  213. float alpha = MathHelper.Lerp(1f - TransitionAlpha, 1f, pauseAlpha / 2);
  214. ScreenManager.FadeBackBufferToBlack(alpha);
  215. }
  216. }
  217. }
  218. }