#region File Description //----------------------------------------------------------------------------- // GameplayScreen.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- #endregion #region Using Statements using System; using System.Threading; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Net; using Microsoft.Xna.Framework.Media; #endregion namespace NetRumble { /// /// This screen implements the actual game logic. /// /// /// This public class is somewhat similar to one of the same name in the /// GameStateManagement sample. /// public class GameplayScreen : GameScreen, IDisposable { #region Gameplay Data /// /// The primary gameplay object. /// private World world; /// /// The ship for the local player. /// private Ship localShip; /// /// The game-winner text. /// private string winnerString = String.Empty; /// /// The position of the game-winner text. /// private Vector2 winnerStringPosition; #endregion #region Graphics Data /// /// The bloom component, applied to part of the game world. /// private BloomComponent bloomComponent; /// /// The starfield, rendering behind the game. /// private Starfield starfield; #endregion #region Networking Data /// /// The network session used in this game. /// private NetworkSession networkSession; /// /// Event handler for the session-ended event. /// EventHandler sessionEndedHandler; /// /// Event handler for the game-ended event. /// EventHandler gameEndedHandler; /// /// Event handler for the gamer-left event. /// EventHandler gamerLeftHandler; #endregion #region Initialization Methods /// /// Construct a new GameplayScreen object. /// /// The network session for this game. /// The primary gameplay object. public GameplayScreen(NetworkSession networkSession, World world) { // safety-check the parameters if (networkSession == null) { throw new ArgumentNullException("networkSession"); } if (world == null) { throw new ArgumentNullException("world"); } // apply the parameters this.networkSession = networkSession; this.world = world; // set up the network events sessionEndedHandler = new EventHandler( networkSession_SessionEnded); networkSession.SessionEnded += sessionEndedHandler; gameEndedHandler = new EventHandler( networkSession_GameEnded); networkSession.GameEnded += gameEndedHandler; gamerLeftHandler = new EventHandler( networkSession_GamerLeft); networkSession.GamerLeft += gamerLeftHandler; // cache the local player's ship object if (networkSession.LocalGamers.Count > 0) { PlayerData playerData = networkSession.LocalGamers[0].Tag as PlayerData; if (playerData != null) { localShip = playerData.Ship; } } // set the transition times TransitionOnTime = TimeSpan.FromSeconds(1.0); TransitionOffTime = TimeSpan.FromSeconds(1.0); } /// /// Load graphics content for the game. /// public override void LoadContent() { // Developers Comment or uncomment the bloomComponent to run with effects or not // *************************** // Comment or uncomment from here // *************************** // create and add the bloom effect #if !BLOOM bloomComponent = new BloomComponent(ScreenManager.Game); bloomComponent.Settings = BloomSettings.PresetSettings[0]; ScreenManager.Game.Components.Add(bloomComponent); bloomComponent.Initialize(); bloomComponent.Visible = false; // we want to control when bloom component is drawn #endif // *************************** // Comment or uncomment to here // *************************** // create the starfield starfield = new Starfield(Vector2.Zero, ScreenManager.GraphicsDevice, ScreenManager.Content); starfield.LoadContent(); // start the background soundtrack AudioManager.PlaySoundTrack(); base.LoadContent(); } /// /// Release graphics data. /// public override void UnloadContent() { if (starfield != null) { starfield.UnloadContent(); } base.UnloadContent(); } #endregion #region Updating Methods /// /// Updates the state of the game. This method checks the GameScreen.IsActive /// property, so the game will stop updating when the pause menu is active, /// or if you tab away to a different application. /// public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen) { base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen); // if something else has canceled our game, then exit if ((networkSession == null) || (world == null)) { if (!IsExiting) { ExitScreen(); } base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen); return; } // update the world if (world != null) { if (otherScreenHasFocus || coveredByOtherScreen) { world.Update((float)gameTime.ElapsedGameTime.TotalSeconds, true); } else if (world.GameExited) { if (!IsExiting) { ExitScreen(); } networkSession = null; base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen); return; } else { world.Update((float)gameTime.ElapsedGameTime.TotalSeconds, false); // if the game was just won, then build the winner string if (world.GameWon && String.IsNullOrEmpty(winnerString) && (world.WinnerIndex >= 0) && (world.WinnerIndex < networkSession.AllGamers.Count)) { winnerString = networkSession.AllGamers[world.WinnerIndex].Gamertag; winnerString += " has won the game!\nPress A to return to the lobby."; Vector2 winnerStringSize = world.PlayerFont.MeasureString(winnerString); winnerStringPosition = new Vector2( ScreenManager.GraphicsDevice.Viewport.X + ScreenManager.GraphicsDevice.Viewport.Width / 2 - (float)Math.Floor(winnerStringSize.X / 2), ScreenManager.GraphicsDevice.Viewport.Y + ScreenManager.GraphicsDevice.Viewport.Height / 2 - (float)Math.Floor(winnerStringSize.Y / 2)); } } } } /// /// Lets the game respond to player input. Unlike the Update method, /// this will only be called when the gameplay screen is active. /// public override void HandleInput(InputState input) { if (input == null) throw new ArgumentNullException("input"); if (!IsExiting) { if ((world != null) && !world.GameExited) { if (input.PauseGame && !world.GameWon) { // If they pressed pause, bring up the pause menu screen. const string message = "Exit the game?"; MessageBoxScreen messageBox = new MessageBoxScreen(message, false); messageBox.Accepted += ExitMessageBoxAccepted; ScreenManager.AddScreen(messageBox); } if (input.MenuSelect && world.GameWon) { world.GameExited = true; world = null; if (!IsExiting) { ExitScreen(); } networkSession = null; } } } } /// /// Event handler for when the user selects "yes" on the "are you sure /// you want to exit" message box. /// private void ExitMessageBoxAccepted(object sender, EventArgs e) { world.GameExited = true; world = null; } /// /// Force the end of a network session so that a new one can be joined. /// public void EndSession() { if (networkSession != null) { networkSession.Dispose(); networkSession = null; } } /// /// Exit this screen. /// public override void ExitScreen() { if (bloomComponent != null) { bloomComponent.Visible = false; ScreenManager.Game.Components.Remove(bloomComponent); bloomComponent = null; } if (!IsExiting && (networkSession != null)) { networkSession.SessionEnded -= sessionEndedHandler; networkSession.GameEnded -= gameEndedHandler; networkSession.GamerLeft -= gamerLeftHandler; } MediaPlayer.Stop(); base.ExitScreen(); } /// /// Screen-specific update to gamer rich presence. /// public override void UpdatePresence() { if (!IsExiting && (networkSession != null)) { bool isTied = (world.HighScorers.Count > 1); for (int i = 0; i < networkSession.AllGamers.Count; ++i) { NetworkGamer networkGamer = networkSession.AllGamers[i]; if (networkGamer.IsLocal) { SignedInGamer signedInGamer = (networkGamer as LocalNetworkGamer).SignedInGamer; if (signedInGamer.IsSignedInToLive) { if (world.HighScorers.Contains(i)) { if (isTied) signedInGamer.Presence.PresenceMode = GamerPresenceMode.ScoreIsTied; else signedInGamer.Presence.PresenceMode = GamerPresenceMode.Winning; } else { signedInGamer.Presence.PresenceMode = GamerPresenceMode.Losing; } } } } } } #endregion #region Drawing Methods /// /// Draws the gameplay screen. /// public override void Draw(GameTime gameTime) { float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds; if (networkSession != null) { // make sure we know what the local ship is if ((localShip == null) && (networkSession.LocalGamers.Count > 0)) { PlayerData playerData = networkSession.LocalGamers[0].Tag as PlayerData; if (playerData.Ship != null) { localShip = playerData.Ship; starfield.Reset(localShip.Position); } } if (bloomComponent != null) { bloomComponent.BeginDraw(); } // draw the world if ((world != null) && (localShip != null) && !IsExiting) { Vector2 center = new Vector2( localShip.Position.X + ScreenManager.GraphicsDevice.Viewport.X - ScreenManager.GraphicsDevice.Viewport.Width / 2, localShip.Position.Y + ScreenManager.GraphicsDevice.Viewport.Y - ScreenManager.GraphicsDevice.Viewport.Height / 2); starfield.Draw(center); world.Draw(elapsedTime, center); if (bloomComponent != null) { bloomComponent.Draw(gameTime); } } // draw the user-interface elements of the game (scores, etc.) DrawHud((float)gameTime.TotalGameTime.TotalSeconds); } // If the game is transitioning on or off, fade it out to black. if (ScreenState == ScreenState.TransitionOn && (TransitionPosition > 0)) ScreenManager.FadeBackBufferToBlack(255 - TransitionAlpha); } /// /// Draw the user interface elements of the game (scores, etc.). /// /// The amount of elapsed time, in seconds. private void DrawHud(float totalTime) { if ((networkSession != null) && (world != null)) { ScreenManager.SpriteBatch.Begin(); // draw players 0 - 3 at the top of the screen Vector2 position = new Vector2( ScreenManager.GraphicsDevice.Viewport.Width * 0.2f, ScreenManager.GraphicsDevice.Viewport.Height * 0.1f); for (int i = 0; i < Math.Min(4, networkSession.AllGamers.Count); i++) { world.DrawPlayerData(totalTime, networkSession.AllGamers[i], position, ScreenManager.SpriteBatch, false); position.X += ScreenManager.GraphicsDevice.Viewport.Width * 0.2f; } // draw players 4 - 7 at the bottom of the screen position = new Vector2( ScreenManager.GraphicsDevice.Viewport.Width * 0.2f, ScreenManager.GraphicsDevice.Viewport.Height * 0.9f); for (int i = 4; i < Math.Min(8, networkSession.AllGamers.Count); i++) { world.DrawPlayerData(totalTime, networkSession.AllGamers[i], position, ScreenManager.SpriteBatch, false); position.X += ScreenManager.GraphicsDevice.Viewport.Width * 0.2f; } // draw players 8 - 11 at the left of the screen position = new Vector2( ScreenManager.GraphicsDevice.Viewport.Width * 0.13f, ScreenManager.GraphicsDevice.Viewport.Height * 0.2f); for (int i = 8; i < Math.Min(12, networkSession.AllGamers.Count); i++) { world.DrawPlayerData(totalTime, networkSession.AllGamers[i], position, ScreenManager.SpriteBatch, false); position.Y += ScreenManager.GraphicsDevice.Viewport.Height * 0.2f; } // draw players 12 - 15 at the right of the screen position = new Vector2( ScreenManager.GraphicsDevice.Viewport.Width * 0.9f, ScreenManager.GraphicsDevice.Viewport.Height * 0.2f); for (int i = 12; i < Math.Min(16, networkSession.AllGamers.Count); i++) { world.DrawPlayerData(totalTime, networkSession.AllGamers[i], position, ScreenManager.SpriteBatch, false); position.Y += ScreenManager.GraphicsDevice.Viewport.Height * 0.2f; } // if the game is over, draw the winner text if (world.GameWon && !String.IsNullOrEmpty(winnerString)) { ScreenManager.SpriteBatch.DrawString(world.PlayerFont, winnerString, winnerStringPosition, Color.White, 0f, Vector2.Zero, 1.3f, SpriteEffects.None, 0f); } ScreenManager.SpriteBatch.End(); } } #endregion #region Networking Event Handlers /// /// Handle the end of the game session. /// void networkSession_GameEnded(object sender, GameEndedEventArgs e) { if ((world != null) && !world.GameWon && !world.GameExited) { world.GameExited = true; } if (!IsExiting && ((world == null) || world.GameExited)) { world = null; ExitScreen(); networkSession = null; } } /// /// Handle the end of the session. /// void networkSession_SessionEnded(object sender, NetworkSessionEndedEventArgs e) { if ((world != null) && !world.GameExited) { world.GameExited = true; world = null; } if (!IsExiting) { ExitScreen(); } networkSession = null; } /// /// Handle a player leaving the game. /// void networkSession_GamerLeft(object sender, GamerLeftEventArgs e) { PlayerData playerData = e.Gamer.Tag as PlayerData; if ((playerData != null) && (playerData.Ship != null)) { playerData.Ship.Die(null, true); } } #endregion #region IDisposable Implementation /// /// Finalizes the GameplayScreen object, calls Dispose(false) /// ~GameplayScreen() { Dispose(false); } /// /// Disposes the GameplayScreen object. /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// Disposes this object. /// /// /// True if this method was called as part of the Dispose method. /// protected virtual void Dispose(bool disposing) { if (disposing) { lock (this) { if (bloomComponent != null) { bloomComponent.Dispose(); bloomComponent = null; } if (starfield != null) { starfield.Dispose(); starfield = null; } } } } #endregion } }