2
0

GameplayScreen.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // GameplayScreen.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.Threading;
  12. using Microsoft.Xna.Framework;
  13. using Microsoft.Xna.Framework.Content;
  14. using Microsoft.Xna.Framework.GamerServices;
  15. using Microsoft.Xna.Framework.Graphics;
  16. using Microsoft.Xna.Framework.Input;
  17. using Microsoft.Xna.Framework.Net;
  18. using Microsoft.Xna.Framework.Media;
  19. #endregion
  20. namespace NetRumble
  21. {
  22. /// <summary>
  23. /// This screen implements the actual game logic.
  24. /// </summary>
  25. /// <remarks>
  26. /// This public class is somewhat similar to one of the same name in the
  27. /// GameStateManagement sample.
  28. /// </remarks>
  29. public class GameplayScreen : GameScreen, IDisposable
  30. {
  31. #region Gameplay Data
  32. /// <summary>
  33. /// The primary gameplay object.
  34. /// </summary>
  35. private World world;
  36. /// <summary>
  37. /// The ship for the local player.
  38. /// </summary>
  39. private Ship localShip;
  40. /// <summary>
  41. /// The game-winner text.
  42. /// </summary>
  43. private string winnerString = String.Empty;
  44. /// <summary>
  45. /// The position of the game-winner text.
  46. /// </summary>
  47. private Vector2 winnerStringPosition;
  48. #endregion
  49. #region Graphics Data
  50. /// <summary>
  51. /// The bloom component, applied to part of the game world.
  52. /// </summary>
  53. private BloomComponent bloomComponent;
  54. /// <summary>
  55. /// The starfield, rendering behind the game.
  56. /// </summary>
  57. private Starfield starfield;
  58. #endregion
  59. #region Networking Data
  60. /// <summary>
  61. /// The network session used in this game.
  62. /// </summary>
  63. private NetworkSession networkSession;
  64. /// <summary>
  65. /// Event handler for the session-ended event.
  66. /// </summary>
  67. EventHandler<NetworkSessionEndedEventArgs> sessionEndedHandler;
  68. /// <summary>
  69. /// Event handler for the game-ended event.
  70. /// </summary>
  71. EventHandler<GameEndedEventArgs> gameEndedHandler;
  72. /// <summary>
  73. /// Event handler for the gamer-left event.
  74. /// </summary>
  75. EventHandler<GamerLeftEventArgs> gamerLeftHandler;
  76. #endregion
  77. #region Initialization Methods
  78. /// <summary>
  79. /// Construct a new GameplayScreen object.
  80. /// </summary>
  81. /// <param name="networkSession">The network session for this game.</param>
  82. /// <param name="world">The primary gameplay object.</param>
  83. public GameplayScreen(NetworkSession networkSession, World world)
  84. {
  85. // safety-check the parameters
  86. if (networkSession == null)
  87. {
  88. throw new ArgumentNullException("networkSession");
  89. }
  90. if (world == null)
  91. {
  92. throw new ArgumentNullException("world");
  93. }
  94. // apply the parameters
  95. this.networkSession = networkSession;
  96. this.world = world;
  97. // set up the network events
  98. sessionEndedHandler = new EventHandler<NetworkSessionEndedEventArgs>(
  99. networkSession_SessionEnded);
  100. networkSession.SessionEnded += sessionEndedHandler;
  101. gameEndedHandler = new EventHandler<GameEndedEventArgs>(
  102. networkSession_GameEnded);
  103. networkSession.GameEnded += gameEndedHandler;
  104. gamerLeftHandler = new EventHandler<GamerLeftEventArgs>(
  105. networkSession_GamerLeft);
  106. networkSession.GamerLeft += gamerLeftHandler;
  107. // cache the local player's ship object
  108. if (networkSession.LocalGamers.Count > 0)
  109. {
  110. PlayerData playerData = networkSession.LocalGamers[0].Tag as PlayerData;
  111. if (playerData != null)
  112. {
  113. localShip = playerData.Ship;
  114. }
  115. }
  116. // set the transition times
  117. TransitionOnTime = TimeSpan.FromSeconds(1.0);
  118. TransitionOffTime = TimeSpan.FromSeconds(1.0);
  119. }
  120. /// <summary>
  121. /// Load graphics content for the game.
  122. /// </summary>
  123. public override void LoadContent()
  124. {
  125. // Developers Comment or uncomment the bloomComponent to run with effects or not
  126. // ***************************
  127. // Comment or uncomment from here
  128. // ***************************
  129. // create and add the bloom effect
  130. #if !BLOOM
  131. bloomComponent = new BloomComponent(ScreenManager.Game);
  132. bloomComponent.Settings = BloomSettings.PresetSettings[0];
  133. ScreenManager.Game.Components.Add(bloomComponent);
  134. bloomComponent.Initialize();
  135. bloomComponent.Visible = false; // we want to control when bloom component is drawn
  136. #endif
  137. // ***************************
  138. // Comment or uncomment to here
  139. // ***************************
  140. // create the starfield
  141. starfield = new Starfield(Vector2.Zero, ScreenManager.GraphicsDevice,
  142. ScreenManager.Content);
  143. starfield.LoadContent();
  144. // start the background soundtrack
  145. AudioManager.PlaySoundTrack();
  146. base.LoadContent();
  147. }
  148. /// <summary>
  149. /// Release graphics data.
  150. /// </summary>
  151. public override void UnloadContent()
  152. {
  153. if (starfield != null)
  154. {
  155. starfield.UnloadContent();
  156. }
  157. base.UnloadContent();
  158. }
  159. #endregion
  160. #region Updating Methods
  161. /// <summary>
  162. /// Updates the state of the game. This method checks the GameScreen.IsActive
  163. /// property, so the game will stop updating when the pause menu is active,
  164. /// or if you tab away to a different application.
  165. /// </summary>
  166. public override void Update(GameTime gameTime, bool otherScreenHasFocus,
  167. bool coveredByOtherScreen)
  168. {
  169. base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
  170. // if something else has canceled our game, then exit
  171. if ((networkSession == null) || (world == null))
  172. {
  173. if (!IsExiting)
  174. {
  175. ExitScreen();
  176. }
  177. base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
  178. return;
  179. }
  180. // update the world
  181. if (world != null)
  182. {
  183. if (otherScreenHasFocus || coveredByOtherScreen)
  184. {
  185. world.Update((float)gameTime.ElapsedGameTime.TotalSeconds, true);
  186. }
  187. else if (world.GameExited)
  188. {
  189. if (!IsExiting)
  190. {
  191. ExitScreen();
  192. }
  193. networkSession = null;
  194. base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
  195. return;
  196. }
  197. else
  198. {
  199. world.Update((float)gameTime.ElapsedGameTime.TotalSeconds, false);
  200. // if the game was just won, then build the winner string
  201. if (world.GameWon && String.IsNullOrEmpty(winnerString) &&
  202. (world.WinnerIndex >= 0) &&
  203. (world.WinnerIndex < networkSession.AllGamers.Count))
  204. {
  205. winnerString =
  206. networkSession.AllGamers[world.WinnerIndex].Gamertag;
  207. winnerString +=
  208. " has won the game!\nPress A to return to the lobby.";
  209. Vector2 winnerStringSize =
  210. world.PlayerFont.MeasureString(winnerString);
  211. winnerStringPosition = new Vector2(
  212. ScreenManager.GraphicsDevice.Viewport.X +
  213. ScreenManager.GraphicsDevice.Viewport.Width / 2 -
  214. (float)Math.Floor(winnerStringSize.X / 2),
  215. ScreenManager.GraphicsDevice.Viewport.Y +
  216. ScreenManager.GraphicsDevice.Viewport.Height / 2 -
  217. (float)Math.Floor(winnerStringSize.Y / 2));
  218. }
  219. }
  220. }
  221. }
  222. /// <summary>
  223. /// Lets the game respond to player input. Unlike the Update method,
  224. /// this will only be called when the gameplay screen is active.
  225. /// </summary>
  226. public override void HandleInput(InputState input)
  227. {
  228. if (input == null)
  229. throw new ArgumentNullException("input");
  230. if (!IsExiting)
  231. {
  232. if ((world != null) && !world.GameExited)
  233. {
  234. if (input.PauseGame && !world.GameWon)
  235. {
  236. // If they pressed pause, bring up the pause menu screen.
  237. const string message = "Exit the game?";
  238. MessageBoxScreen messageBox = new MessageBoxScreen(message,
  239. false);
  240. messageBox.Accepted += ExitMessageBoxAccepted;
  241. ScreenManager.AddScreen(messageBox);
  242. }
  243. if (input.MenuSelect && world.GameWon)
  244. {
  245. world.GameExited = true;
  246. world = null;
  247. if (!IsExiting)
  248. {
  249. ExitScreen();
  250. }
  251. networkSession = null;
  252. }
  253. }
  254. }
  255. }
  256. /// <summary>
  257. /// Event handler for when the user selects "yes" on the "are you sure
  258. /// you want to exit" message box.
  259. /// </summary>
  260. private void ExitMessageBoxAccepted(object sender, EventArgs e)
  261. {
  262. world.GameExited = true;
  263. world = null;
  264. }
  265. /// <summary>
  266. /// Force the end of a network session so that a new one can be joined.
  267. /// </summary>
  268. public void EndSession()
  269. {
  270. if (networkSession != null)
  271. {
  272. networkSession.Dispose();
  273. networkSession = null;
  274. }
  275. }
  276. /// <summary>
  277. /// Exit this screen.
  278. /// </summary>
  279. public override void ExitScreen()
  280. {
  281. if (bloomComponent != null)
  282. {
  283. bloomComponent.Visible = false;
  284. ScreenManager.Game.Components.Remove(bloomComponent);
  285. bloomComponent = null;
  286. }
  287. if (!IsExiting && (networkSession != null))
  288. {
  289. networkSession.SessionEnded -= sessionEndedHandler;
  290. networkSession.GameEnded -= gameEndedHandler;
  291. networkSession.GamerLeft -= gamerLeftHandler;
  292. }
  293. MediaPlayer.Stop();
  294. base.ExitScreen();
  295. }
  296. /// <summary>
  297. /// Screen-specific update to gamer rich presence.
  298. /// </summary>
  299. public override void UpdatePresence()
  300. {
  301. if (!IsExiting && (networkSession != null))
  302. {
  303. bool isTied = (world.HighScorers.Count > 1);
  304. for (int i = 0; i < networkSession.AllGamers.Count; ++i)
  305. {
  306. NetworkGamer networkGamer = networkSession.AllGamers[i];
  307. if (networkGamer.IsLocal)
  308. {
  309. SignedInGamer signedInGamer = (networkGamer as LocalNetworkGamer).SignedInGamer;
  310. if (signedInGamer.IsSignedInToLive)
  311. {
  312. if (world.HighScorers.Contains(i))
  313. {
  314. if (isTied)
  315. signedInGamer.Presence.PresenceMode = GamerPresenceMode.ScoreIsTied;
  316. else
  317. signedInGamer.Presence.PresenceMode = GamerPresenceMode.Winning;
  318. }
  319. else
  320. {
  321. signedInGamer.Presence.PresenceMode = GamerPresenceMode.Losing;
  322. }
  323. }
  324. }
  325. }
  326. }
  327. }
  328. #endregion
  329. #region Drawing Methods
  330. /// <summary>
  331. /// Draws the gameplay screen.
  332. /// </summary>
  333. public override void Draw(GameTime gameTime)
  334. {
  335. float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
  336. if (networkSession != null)
  337. {
  338. // make sure we know what the local ship is
  339. if ((localShip == null) && (networkSession.LocalGamers.Count > 0))
  340. {
  341. PlayerData playerData = networkSession.LocalGamers[0].Tag
  342. as PlayerData;
  343. if (playerData.Ship != null)
  344. {
  345. localShip = playerData.Ship;
  346. starfield.Reset(localShip.Position);
  347. }
  348. }
  349. if (bloomComponent != null)
  350. {
  351. bloomComponent.BeginDraw();
  352. }
  353. // draw the world
  354. if ((world != null) && (localShip != null) && !IsExiting)
  355. {
  356. Vector2 center = new Vector2(
  357. localShip.Position.X + ScreenManager.GraphicsDevice.Viewport.X -
  358. ScreenManager.GraphicsDevice.Viewport.Width / 2,
  359. localShip.Position.Y + ScreenManager.GraphicsDevice.Viewport.Y -
  360. ScreenManager.GraphicsDevice.Viewport.Height / 2);
  361. starfield.Draw(center);
  362. world.Draw(elapsedTime, center);
  363. if (bloomComponent != null)
  364. {
  365. bloomComponent.Draw(gameTime);
  366. }
  367. }
  368. // draw the user-interface elements of the game (scores, etc.)
  369. DrawHud((float)gameTime.TotalGameTime.TotalSeconds);
  370. }
  371. // If the game is transitioning on or off, fade it out to black.
  372. if (ScreenState == ScreenState.TransitionOn && (TransitionPosition > 0))
  373. ScreenManager.FadeBackBufferToBlack(255 - TransitionAlpha);
  374. }
  375. /// <summary>
  376. /// Draw the user interface elements of the game (scores, etc.).
  377. /// </summary>
  378. /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
  379. private void DrawHud(float totalTime)
  380. {
  381. if ((networkSession != null) && (world != null))
  382. {
  383. ScreenManager.SpriteBatch.Begin();
  384. // draw players 0 - 3 at the top of the screen
  385. Vector2 position = new Vector2(
  386. ScreenManager.GraphicsDevice.Viewport.Width * 0.2f,
  387. ScreenManager.GraphicsDevice.Viewport.Height * 0.1f);
  388. for (int i = 0; i < Math.Min(4, networkSession.AllGamers.Count); i++)
  389. {
  390. world.DrawPlayerData(totalTime, networkSession.AllGamers[i],
  391. position, ScreenManager.SpriteBatch, false);
  392. position.X += ScreenManager.GraphicsDevice.Viewport.Width * 0.2f;
  393. }
  394. // draw players 4 - 7 at the bottom of the screen
  395. position = new Vector2(
  396. ScreenManager.GraphicsDevice.Viewport.Width * 0.2f,
  397. ScreenManager.GraphicsDevice.Viewport.Height * 0.9f);
  398. for (int i = 4; i < Math.Min(8, networkSession.AllGamers.Count); i++)
  399. {
  400. world.DrawPlayerData(totalTime, networkSession.AllGamers[i],
  401. position, ScreenManager.SpriteBatch, false);
  402. position.X += ScreenManager.GraphicsDevice.Viewport.Width * 0.2f;
  403. }
  404. // draw players 8 - 11 at the left of the screen
  405. position = new Vector2(
  406. ScreenManager.GraphicsDevice.Viewport.Width * 0.13f,
  407. ScreenManager.GraphicsDevice.Viewport.Height * 0.2f);
  408. for (int i = 8; i < Math.Min(12, networkSession.AllGamers.Count); i++)
  409. {
  410. world.DrawPlayerData(totalTime, networkSession.AllGamers[i],
  411. position, ScreenManager.SpriteBatch, false);
  412. position.Y += ScreenManager.GraphicsDevice.Viewport.Height * 0.2f;
  413. }
  414. // draw players 12 - 15 at the right of the screen
  415. position = new Vector2(
  416. ScreenManager.GraphicsDevice.Viewport.Width * 0.9f,
  417. ScreenManager.GraphicsDevice.Viewport.Height * 0.2f);
  418. for (int i = 12; i < Math.Min(16, networkSession.AllGamers.Count); i++)
  419. {
  420. world.DrawPlayerData(totalTime, networkSession.AllGamers[i],
  421. position, ScreenManager.SpriteBatch, false);
  422. position.Y += ScreenManager.GraphicsDevice.Viewport.Height * 0.2f;
  423. }
  424. // if the game is over, draw the winner text
  425. if (world.GameWon && !String.IsNullOrEmpty(winnerString))
  426. {
  427. ScreenManager.SpriteBatch.DrawString(world.PlayerFont, winnerString,
  428. winnerStringPosition, Color.White, 0f, Vector2.Zero, 1.3f,
  429. SpriteEffects.None, 0f);
  430. }
  431. ScreenManager.SpriteBatch.End();
  432. }
  433. }
  434. #endregion
  435. #region Networking Event Handlers
  436. /// <summary>
  437. /// Handle the end of the game session.
  438. /// </summary>
  439. void networkSession_GameEnded(object sender, GameEndedEventArgs e)
  440. {
  441. if ((world != null) && !world.GameWon && !world.GameExited)
  442. {
  443. world.GameExited = true;
  444. }
  445. if (!IsExiting && ((world == null) || world.GameExited))
  446. {
  447. world = null;
  448. ExitScreen();
  449. networkSession = null;
  450. }
  451. }
  452. /// <summary>
  453. /// Handle the end of the session.
  454. /// </summary>
  455. void networkSession_SessionEnded(object sender, NetworkSessionEndedEventArgs e)
  456. {
  457. if ((world != null) && !world.GameExited)
  458. {
  459. world.GameExited = true;
  460. world = null;
  461. }
  462. if (!IsExiting)
  463. {
  464. ExitScreen();
  465. }
  466. networkSession = null;
  467. }
  468. /// <summary>
  469. /// Handle a player leaving the game.
  470. /// </summary>
  471. void networkSession_GamerLeft(object sender, GamerLeftEventArgs e)
  472. {
  473. PlayerData playerData = e.Gamer.Tag as PlayerData;
  474. if ((playerData != null) && (playerData.Ship != null))
  475. {
  476. playerData.Ship.Die(null, true);
  477. }
  478. }
  479. #endregion
  480. #region IDisposable Implementation
  481. /// <summary>
  482. /// Finalizes the GameplayScreen object, calls Dispose(false)
  483. /// </summary>
  484. ~GameplayScreen()
  485. {
  486. Dispose(false);
  487. }
  488. /// <summary>
  489. /// Disposes the GameplayScreen object.
  490. /// </summary>
  491. public void Dispose()
  492. {
  493. Dispose(true);
  494. GC.SuppressFinalize(this);
  495. }
  496. /// <summary>
  497. /// Disposes this object.
  498. /// </summary>
  499. /// <param name="disposing">
  500. /// True if this method was called as part of the Dispose method.
  501. /// </param>
  502. protected virtual void Dispose(bool disposing)
  503. {
  504. if (disposing)
  505. {
  506. lock (this)
  507. {
  508. if (bloomComponent != null)
  509. {
  510. bloomComponent.Dispose();
  511. bloomComponent = null;
  512. }
  513. if (starfield != null)
  514. {
  515. starfield.Dispose();
  516. starfield = null;
  517. }
  518. }
  519. }
  520. }
  521. #endregion
  522. }
  523. }