#region File Description //----------------------------------------------------------------------------- // LobbyScreen.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- #endregion #region Using Statements using System; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Net; #endregion namespace NetworkStateManagement { /// /// The lobby screen provides a place for gamers to congregate before starting /// the actual gameplay. It displays a list of all the gamers in the session, /// and indicates which ones are currently talking. Each gamer can press a button /// to mark themselves as ready: gameplay will begin after everyone has done this. /// class LobbyScreen : GameScreen { #region Fields NetworkSession networkSession; Texture2D isReadyTexture; Texture2D hasVoiceTexture; Texture2D isTalkingTexture; Texture2D voiceMutedTexture; #endregion #region Initialization /// /// Constructs a new lobby screen. /// public LobbyScreen (NetworkSession networkSession) { this.networkSession = networkSession; TransitionOnTime = TimeSpan.FromSeconds (0.5); TransitionOffTime = TimeSpan.FromSeconds (0.5); } /// /// Loads graphics content used by the lobby screen. /// public override void LoadContent () { ContentManager content = ScreenManager.Game.Content; isReadyTexture = content.Load ("chat_ready"); hasVoiceTexture = content.Load ("chat_able"); isTalkingTexture = content.Load ("chat_talking"); voiceMutedTexture = content.Load ("chat_mute"); } #endregion #region Update /// /// Updates the lobby screen. /// public override void Update (GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen) { base.Update (gameTime, otherScreenHasFocus, coveredByOtherScreen); if (!IsExiting) { if (networkSession.SessionState == NetworkSessionState.Playing) { // Check if we should leave the lobby and begin gameplay. // We pass null as the controlling player, because the networked // gameplay screen accepts input from any local players who // are in the session, not just a single controlling player. LoadingScreen.Load (ScreenManager, true, null, new GameplayScreen (networkSession)); } else if (networkSession.IsHost && networkSession.IsEveryoneReady) { // The host checks whether everyone has marked themselves // as ready, and starts the game in response. networkSession.StartGame (); } } } /// /// Handles user input for all the local gamers in the session. Unlike most /// screens, which use the InputState class to combine input data from all /// gamepads, the lobby needs to individually mark specific players as ready, /// so it loops over all the local gamers and reads their inputs individually. /// public override void HandleInput (InputState input) { foreach (LocalNetworkGamer gamer in networkSession.LocalGamers) { PlayerIndex playerIndex = gamer.SignedInGamer.PlayerIndex; PlayerIndex unwantedOutput; if (input.IsMenuSelect (playerIndex, out unwantedOutput)) { HandleMenuSelect (gamer); } else if (input.IsMenuCancel (playerIndex, out unwantedOutput)) { HandleMenuCancel (gamer); } } } /// /// Handle MenuSelect inputs by marking ourselves as ready. /// void HandleMenuSelect (LocalNetworkGamer gamer) { if (!gamer.IsReady) { gamer.IsReady = true; } else if (gamer.IsHost) { // The host has an option to force starting the game, even if not // everyone has marked themselves ready. If they press select twice // in a row, the first time marks the host ready, then the second // time we ask if they want to force start. MessageBoxScreen messageBox = new MessageBoxScreen ( Resources.ConfirmForceStartGame); messageBox.Accepted += ConfirmStartGameMessageBoxAccepted; ScreenManager.AddScreen (messageBox, gamer.SignedInGamer.PlayerIndex); } } /// /// Event handler for when the host selects ok on the "are you sure /// you want to start even though not everyone is ready" message box. /// void ConfirmStartGameMessageBoxAccepted (object sender, PlayerIndexEventArgs e) { if (networkSession.SessionState == NetworkSessionState.Lobby) { networkSession.StartGame (); } } /// /// Handle MenuCancel inputs by clearing our ready status, or if it is /// already clear, prompting if the user wants to leave the session. /// void HandleMenuCancel (LocalNetworkGamer gamer) { if (gamer.IsReady) { gamer.IsReady = false; } else { PlayerIndex playerIndex = gamer.SignedInGamer.PlayerIndex; NetworkSessionComponent.LeaveSession (ScreenManager, playerIndex); } } #endregion #region Draw /// /// Draws the lobby screen. /// public override void Draw (GameTime gameTime) { SpriteBatch spriteBatch = ScreenManager.SpriteBatch; SpriteFont font = ScreenManager.Font; Vector2 position = new Vector2 (100, 150); // Make the lobby slide into place during transitions. float transitionOffset = (float)Math.Pow (TransitionPosition, 2); if (ScreenState == ScreenState.TransitionOn) position.X -= transitionOffset * 256; else position.X += transitionOffset * 512; spriteBatch.Begin (); // Draw all the gamers in the session. int gamerCount = 0; foreach (NetworkGamer gamer in networkSession.AllGamers) { DrawGamer (gamer, position); // Advance to the next screen position, wrapping into two // columns if there are more than 8 gamers in the session. if (++gamerCount == 8) { position.X += 433; position.Y = 150; } else position.Y += ScreenManager.Font.LineSpacing; } // Draw the screen title. string title = Resources.Lobby; Vector2 titlePosition = new Vector2 (533, 80); Vector2 titleOrigin = font.MeasureString (title) / 2; Color titleColor = new Color (192, 192, 192) * TransitionAlpha; float titleScale = 1.25f; titlePosition.Y -= transitionOffset * 100; spriteBatch.DrawString (font, title, titlePosition, titleColor, 0, titleOrigin, titleScale, SpriteEffects.None, 0); spriteBatch.End (); } /// /// Helper draws the gamertag and status icons for a single NetworkGamer. /// void DrawGamer (NetworkGamer gamer, Vector2 position) { SpriteBatch spriteBatch = ScreenManager.SpriteBatch; SpriteFont font = ScreenManager.Font; Vector2 iconWidth = new Vector2 (34, 0); Vector2 iconOffset = new Vector2 (0, 12); Vector2 iconPosition = position + iconOffset; // Draw the "is ready" icon. if (gamer.IsReady) { spriteBatch.Draw (isReadyTexture, iconPosition, Color.Lime * TransitionAlpha); } iconPosition += iconWidth; // Draw the "is muted", "is talking", or "has voice" icon. if (gamer.IsMutedByLocalUser) { spriteBatch.Draw (voiceMutedTexture, iconPosition, Color.Red * TransitionAlpha); } else if (gamer.IsTalking) { spriteBatch.Draw (isTalkingTexture, iconPosition, Color.Yellow * TransitionAlpha); } else if (gamer.HasVoice) { spriteBatch.Draw (hasVoiceTexture, iconPosition, Color.White * TransitionAlpha); } // Draw the gamertag, normally in white, but yellow for local players. string text = gamer.Gamertag; if (gamer.IsHost) text += Resources.HostSuffix; Color color = (gamer.IsLocal) ? Color.Yellow : Color.White; spriteBatch.DrawString (font, text, position + iconWidth * 2, color * TransitionAlpha); } #endregion } }