using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Xna.Framework.Net; using System.Diagnostics; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Content; namespace CarFire { public class ScreenManager : IScreenManager { #region local variables float scale; Texture2D background; Texture2D spotLight; Texture2D cs; Texture2D selectGameScreen; Vector2 backgroundPos; Vector2 spotLightPos; Vector2 spotLightCenter; Vector2 csPos; Vector2 zero; Vector2 spotLightVelocity; int MaxX; int MinX; int MaxY; int MinY; Texture2D checkedBox; Texture2D deselectBox; Texture2D emptySelectBox; Texture2D menuItem; Boolean ready; SpriteFont menuFont; string selected; Vector2 createGamePos; string createGameText; Vector2 findGamePos; string findGameText; Vector2 returnToMainPos; string returnToMainText; KeyboardState previousKeyboardState; KeyboardState currentKeyboardState; GamerCollection players; LocalNetworkGamer localPlayer; AvailableNetworkSessionCollection availableSessions; bool allReady; int selectedSessionIndex; bool chatActive; String chatMessage; Queue currentChat; private enum lobbyState { Welcome, CreateGame, FindGame, FindingGames, // TODO: New state. JoiningGame, // TODO: New state. Connected } lobbyState currentState; #endregion public ScreenManager() { currentState = lobbyState.Welcome; selectedSessionIndex = 0; ready = false; chatActive = false; chatMessage = ""; currentChat = new Queue(); } public void LoadContent(ContentManager contentManager, GraphicsDeviceManager graphics) { background = contentManager.Load("background"); spotLight = contentManager.Load("spotlight"); cs = contentManager.Load("cs"); selectGameScreen = contentManager.Load("selectGameScreen"); backgroundPos = new Vector2(0f, 0f); spotLightPos = new Vector2(100f, graphics.GraphicsDevice.Viewport.Height - 98); spotLightCenter = new Vector2(800f, 800f); spotLightVelocity = new Vector2(-100, 33); csPos = new Vector2(10f, graphics.GraphicsDevice.Viewport.Height - 98); zero = new Vector2(0, 0); MaxX = graphics.GraphicsDevice.Viewport.Width; MinX = 0; MaxY = graphics.GraphicsDevice.Viewport.Height; MinY = 100; scale = MaxX / 1600f; //playerlist stuff checkedBox = contentManager.Load("checkedBox"); deselectBox = contentManager.Load("deselectBox"); emptySelectBox = contentManager.Load("emptySelectBox"); menuItem = contentManager.Load("menuItem"); //menu fonts menuFont = contentManager.Load("menuFont"); createGamePos = new Vector2(100f, MaxY / 3); createGameText = "Create Game"; selected = createGameText; findGamePos = new Vector2(100f, (MaxY / 3) + 60); findGameText = "Find Game"; returnToMainPos = new Vector2(MaxX / 2, MaxY - 120); returnToMainText = "press [ X ] to return to main menu"; } public void UnloadContent() { } /// /// Transition into connected state /// void JoinedSession(NetworkSession session, NetworkManager networkManager) { if (session != null) { currentState = lobbyState.Connected; } else { // TODO: This should do something more than just throw the player back to the welcome screen. currentState = lobbyState.Welcome; Console.WriteLine("Couldn't create/join the session."); } } /// /// Called when Async FindSession returns. Available sessions is then updated /// void FoundSessions(AvailableNetworkSessionCollection sessions, NetworkManager networkManager) { availableSessions = sessions; } /// /// Catches exceptions for and Async calls /// void AsyncCallbackFailed(Exception exception, NetworkManager networkManager) { currentState = lobbyState.Welcome; Console.WriteLine("Exception as thrown during async call: " + exception.Message); } /// /// Adds and new chats to the chat list. If chat list is full, older messages are removed. /// private void UpdateChat(GameTime gameTime, NetworkManager networkManager) { List chts = networkManager.ReceiveChats(); for (int x = 0; x < chts.Count(); x++) currentChat.Enqueue(chts[x]); //if number of chat messages has reached max remove older messages as new ones are added if (currentChat.Count() > 8) { for (int x = 0; x < chts.Count(); x++) { currentChat.Dequeue(); } } } /// /// Main update call for Lobby, what is actually updated is determined by what the current state is. /// public long Update(GameTime gameTime, NetworkManager networkManager) { UpdateSpotLight(gameTime); currentKeyboardState = Keyboard.GetState(); if (networkManager.HasActiveSession) { players = networkManager.NetworkGamers; } //check inputs switch (currentState) { case lobbyState.Welcome: if (selected == createGameText) { if (currentKeyboardState.IsKeyDown(Keys.Enter) && previousKeyboardState.IsKeyUp(Keys.Enter)) currentState = lobbyState.CreateGame; if (currentKeyboardState.IsKeyDown(Keys.Down)) selected = findGameText; } else { if (currentKeyboardState.IsKeyDown(Keys.Enter) && previousKeyboardState.IsKeyUp(Keys.Enter)) currentState = lobbyState.FindGame; if (currentKeyboardState.IsKeyDown(Keys.Up)) selected = createGameText; } break; case lobbyState.CreateGame: if (currentKeyboardState.IsKeyDown(Keys.X) && previousKeyboardState.IsKeyUp(Keys.X)) { currentState = lobbyState.Welcome; ready = false; if (networkManager.HasActiveSession) { players = null; networkManager.LeaveSession(); } } if (currentKeyboardState.IsKeyDown(Keys.Y) && previousKeyboardState.IsKeyUp(Keys.Y)) { currentState = lobbyState.JoiningGame; networkManager.ErrorDelegate = AsyncCallbackFailed; networkManager.CreateSession(JoinedSession); } break; case lobbyState.FindGame: if (currentKeyboardState.IsKeyDown(Keys.X) && previousKeyboardState.IsKeyUp(Keys.X)) { currentState = lobbyState.Welcome; ready = false; } availableSessions = null; networkManager.ErrorDelegate = AsyncCallbackFailed; networkManager.FindSessions(FoundSessions); currentState = lobbyState.FindingGames; break; case lobbyState.FindingGames: if (currentKeyboardState.IsKeyDown(Keys.X) && previousKeyboardState.IsKeyUp(Keys.X)) { currentState = lobbyState.Welcome; ready = false; } if (availableSessions != null && availableSessions.Count == 0) currentState = lobbyState.FindGame; else if (availableSessions != null && availableSessions.Count > 0) { if (currentKeyboardState.IsKeyDown(Keys.D1) && previousKeyboardState.IsKeyUp(Keys.D1)) { networkManager.JoinSession(availableSessions[0], JoinedSession); currentState = lobbyState.JoiningGame; availableSessions.Dispose(); availableSessions = null; } if (currentKeyboardState.IsKeyDown(Keys.D2) && previousKeyboardState.IsKeyUp(Keys.D2)) { networkManager.JoinSession(availableSessions[0], JoinedSession); currentState = lobbyState.JoiningGame; availableSessions.Dispose(); availableSessions = null; } } break; case lobbyState.Connected: if (chatActive) //If chat is activated by pressing T all inputs go to chat. Enter finishes chat esc returns { if (currentKeyboardState.IsKeyDown(Keys.Escape) && previousKeyboardState.IsKeyUp(Keys.Escape)) { chatActive = false; break; } if (currentKeyboardState.IsKeyDown(Keys.Enter) && previousKeyboardState.IsKeyUp(Keys.Enter)) { networkManager.SendChat(chatMessage); chatActive = false; break; } Keys[] k = currentKeyboardState.GetPressedKeys(); Keys[] kp = previousKeyboardState.GetPressedKeys(); List newKeys = new List(); for (int x = 0; x < k.Count(); x++) //copy new keys into array { if (!kp.Contains(k[x])) { newKeys.Add(k[x]); } } foreach(Keys ky in newKeys) { if (ky.Equals(Keys.Back)) chatMessage = chatMessage.Substring(0, chatMessage.Length-1); else if(ky.Equals(Keys.Space)) chatMessage = chatMessage + " "; else chatMessage = chatMessage + ky.ToString(); } } else //normal op mode { UpdateChat(gameTime, networkManager); chatMessage = ""; if (currentKeyboardState.IsKeyDown(Keys.T) && previousKeyboardState.IsKeyUp(Keys.T)) { chatActive = true; } if (currentKeyboardState.IsKeyDown(Keys.X) && previousKeyboardState.IsKeyUp(Keys.X)) { ready = false; currentChat.Clear(); if (networkManager.HasActiveSession) { players = null; networkManager.LeaveSession(); } currentState = lobbyState.Welcome; } if (currentKeyboardState.IsKeyDown(Keys.R) && previousKeyboardState.IsKeyUp(Keys.R)) networkManager.LocalGamer.IsReady = true; if (networkManager.HasActiveSession) { localPlayer = networkManager.LocalGamer; players = networkManager.NetworkGamers; if (players != null) { allReady = true; foreach (NetworkGamer p in players) if (p.IsReady == false) { allReady = false; break; } } //allows host to start the game when all players are ready, change count below to different number for testing with less then 4 players if (allReady && players.Count <= 4 && localPlayer == players[0]) { if (currentKeyboardState.IsKeyDown(Keys.B) && previousKeyboardState.IsKeyUp(Keys.B)) { networkManager.ForceStartGame(); } } } else currentState = lobbyState.Welcome; } break; } previousKeyboardState = Keyboard.GetState(); return 1; } /// /// Draws the lobby GUI. Has different states for difference menu configurations /// public long Draw(SpriteBatch spriteBatch) { spriteBatch.Draw(background, backgroundPos, null, Color.White, 0, zero, scale, SpriteEffects.None, 0); spriteBatch.Draw(cs, csPos, null, Color.White, 0, zero, 0.5f, SpriteEffects.None, 0); spriteBatch.Draw(spotLight, spotLightPos, null, Color.White, 0, spotLightCenter, 1f, SpriteEffects.None, 0); switch (currentState) { case lobbyState.Welcome: spriteBatch.DrawString(menuFont, "press [ Home ] to login", new Vector2(350, 20), Color.LightGray, 0f, zero, .6f, SpriteEffects.None, 0.5f); if (selected == createGameText) spriteBatch.DrawString(menuFont, createGameText, createGamePos, Color.Red, 0, zero, 1f, SpriteEffects.None, 0.5f); else spriteBatch.DrawString(menuFont, createGameText, createGamePos, Color.Gray, 0, zero, 1f,SpriteEffects.None, 0.5f); if (selected == findGameText) spriteBatch.DrawString(menuFont, findGameText, findGamePos, Color.Red, 0, zero, 1f, SpriteEffects.None, 0.5f); else spriteBatch.DrawString(menuFont, findGameText, findGamePos, Color.Gray, 0, zero, 1f, SpriteEffects.None, 0.5f); break; case lobbyState.CreateGame: DrawPlayerList(spriteBatch); spriteBatch.DrawString(menuFont, "You are now the Host!", new Vector2(MaxX / 2, MaxY / 3), Color.White, 0f, zero, .7f, SpriteEffects.None, 0.5f); spriteBatch.DrawString(menuFont, "press: Y to continue", new Vector2(MaxX /2, (MaxY / 3) + menuFont.LineSpacing), Color.White, 0f, zero, .6f, SpriteEffects.None, 0.5f); spriteBatch.DrawString(menuFont, "X to return to main menu", new Vector2(MaxX /2 + 40, (MaxY / 3) + 2 * menuFont.LineSpacing), Color.White, 0f, zero, .6f, SpriteEffects.None, 0.5f); break; case lobbyState.FindingGames: spriteBatch.Draw(selectGameScreen, backgroundPos, null, Color.White, 0, zero, scale, SpriteEffects.None, 0); spriteBatch.DrawString(menuFont, "select game by pressing listed games index", new Vector2(250, 400), Color.Gray, 0f, zero, .7f, SpriteEffects.None, 0.5f); if(availableSessions == null) spriteBatch.DrawString(menuFont, "searching for available games ....", new Vector2(150, 100), Color.Gray, 0f, zero, .7f, SpriteEffects.None, 0.5f); else if (availableSessions.Count == 0) spriteBatch.DrawString(menuFont, "no games currently available, searching ....", new Vector2(150, 100), Color.Gray, 0f, zero, .7f, SpriteEffects.None, 0.5f); else { for (int sessionIndex = 0; sessionIndex < availableSessions.Count; sessionIndex++) { Color color = Color.Gray; if (sessionIndex == selectedSessionIndex) color = Color.Red; spriteBatch.DrawString(menuFont, sessionIndex+1 + " " + availableSessions[sessionIndex].HostGamertag, new Vector2(150, 125 + sessionIndex * menuFont.LineSpacing), color, 0f, zero, .7f, SpriteEffects.None, 0.5f); spriteBatch.DrawString(menuFont, availableSessions[sessionIndex].CurrentGamerCount + " / 4", new Vector2(450, 125 + sessionIndex * menuFont.LineSpacing), color, 0f, zero, .7f, SpriteEffects.None, 0.5f); } } break; case lobbyState.Connected: DrawPlayerList(spriteBatch); DrawChatInfo(spriteBatch); if(allReady && players.Count <= 4 && localPlayer == players[0]) spriteBatch.DrawString(menuFont, "Press B to begin game!", new Vector2(MaxX / 2, MaxY / 2), Color.White, 0f, zero, .7f, SpriteEffects.None, 0.5f); else if(allReady) spriteBatch.DrawString(menuFont, "The game will begin soon.", new Vector2(MaxX / 2, MaxY / 2), Color.White, 0f, zero, .7f, SpriteEffects.None, 0.5f); else spriteBatch.DrawString(menuFont, "Waiting for ready players...", new Vector2(MaxX / 2, MaxY / 2), Color.White, 0f, zero, .7f, SpriteEffects.None, 0.5f); break; } return 1; } /// /// Updates backgound animation with moving spotlight. Spotlight bounces off walls /// private void UpdateSpotLight(GameTime gameTime) { spotLightPos = new Vector2(spotLightPos.X + spotLightVelocity.X * (float)gameTime.ElapsedGameTime.TotalSeconds, spotLightPos.Y + spotLightVelocity.Y * (float)gameTime.ElapsedGameTime.TotalSeconds); if (spotLightPos.X > MaxX || spotLightPos.X < MinX) //right or left wall { spotLightVelocity = new Vector2(spotLightVelocity.X * -1, spotLightVelocity.Y); } else if (spotLightPos.Y > MaxY || spotLightPos.Y < MinY) //top or bottom wall { spotLightVelocity = new Vector2(spotLightVelocity.X, spotLightVelocity.Y * -1); } } /// /// Draws the list of current chat messages received by the local client. /// private void DrawChatInfo(SpriteBatch spriteBatch) { if (currentChat.Count > 0) { for (int y = 0; y < currentChat.Count; y++) { spriteBatch.DrawString(menuFont, currentChat.ElementAt(y).Sender + ": " + currentChat.ElementAt(y).Message , new Vector2(400, 10 + y*15), Color.Blue, 0f, zero, .6f, SpriteEffects.None, 1f); } } if(chatActive) spriteBatch.DrawString(menuFont, chatMessage, new Vector2(400, 10 + 15*(currentChat.Count + 1)), Color.Green, 0f, zero, .6f, SpriteEffects.None, 1f); } /// /// Draws player list objects for the connected state. /// private void DrawPlayerList(SpriteBatch spriteBatch) { //reference point Vector2 topOfList = new Vector2(MaxX / 8, MaxY / 4); //command info spriteBatch.DrawString(menuFont, "Current Players", new Vector2(topOfList.X + 15, topOfList.Y - 25), Color.White); spriteBatch.DrawString(menuFont, "Command Options: to mark your self as ready", new Vector2(20, 20), Color.Gray, 0f, zero, .6f, SpriteEffects.None, 1f); spriteBatch.DrawString(menuFont, "type players # to toggle chat", new Vector2(175, 40), Color.Gray, 0f, zero, .6f, SpriteEffects.None, 1f); spriteBatch.DrawString(menuFont, "return to main menu", new Vector2(175, 80), Color.Gray, 0f, zero, .6f, SpriteEffects.None, 1f); spriteBatch.DrawString(menuFont, "enter chat mode", new Vector2(175, 60), Color.Gray, 0f, zero, .6f, SpriteEffects.None, 1f); spriteBatch.DrawString(menuFont, "R", new Vector2(145, 20), Color.DarkGreen, 0f, zero, .6f, SpriteEffects.None, 1f); spriteBatch.DrawString(menuFont, "#", new Vector2(145, 40), Color.DarkGreen, 0f, zero, .6f, SpriteEffects.None, 1f); spriteBatch.DrawString(menuFont, "X", new Vector2(145, 80), Color.DarkGreen, 0f, zero, .6f, SpriteEffects.None, 1f); spriteBatch.DrawString(menuFont, "T", new Vector2(145, 60), Color.DarkGreen, 0f, zero, .6f, SpriteEffects.None, 1f); //Background squares spriteBatch.Draw(menuItem, topOfList, null, Color.White, 0, zero, scale, SpriteEffects.None, 1f); spriteBatch.Draw(menuItem, new Vector2(topOfList.X, topOfList.Y + 65), null, Color.White, 0, zero, scale, SpriteEffects.None, 1f); spriteBatch.Draw(menuItem, new Vector2(topOfList.X, topOfList.Y + 130), null, Color.White, 0, zero, scale, SpriteEffects.None, 1f); spriteBatch.Draw(menuItem, new Vector2(topOfList.X, topOfList.Y + 195), null, Color.White, 0, zero, scale, SpriteEffects.None, 1f); //Ready Labels spriteBatch.DrawString(menuFont, "Ready", new Vector2(topOfList.X + 5, topOfList.Y + 45), Color.DarkGray, 0f, zero, .6f, SpriteEffects.None, 1f); spriteBatch.DrawString(menuFont, "Ready", new Vector2(topOfList.X + 5, topOfList.Y + 110), Color.DarkGray, 0f, zero, .6f, SpriteEffects.None, 1f); spriteBatch.DrawString(menuFont, "Ready", new Vector2(topOfList.X + 5, topOfList.Y + 175), Color.DarkGray, 0f, zero, .6f, SpriteEffects.None, 1f); spriteBatch.DrawString(menuFont, "Ready", new Vector2(topOfList.X + 5, topOfList.Y + 240), Color.DarkGray, 0f, zero, .6f, SpriteEffects.None, 1f); //Ready CheckBoxs if (players == null) { spriteBatch.Draw(emptySelectBox, new Vector2(topOfList.X - 32, topOfList.Y + 35), null, Color.White, 0, zero, scale, SpriteEffects.None, 1f); spriteBatch.Draw(emptySelectBox, new Vector2(topOfList.X - 32, topOfList.Y + 100), null, Color.White, 0, zero, scale, SpriteEffects.None, 1f); spriteBatch.Draw(emptySelectBox, new Vector2(topOfList.X - 32, topOfList.Y + 165), null, Color.White, 0, zero, scale, SpriteEffects.None, 1f); spriteBatch.Draw(emptySelectBox, new Vector2(topOfList.X - 32, topOfList.Y + 230), null, Color.White, 0, zero, scale, SpriteEffects.None, 1f); } else { if (!(players.Count >= 1 && players[0].IsReady)) spriteBatch.Draw(emptySelectBox, new Vector2(topOfList.X - 32, topOfList.Y + 35), null, Color.White, 0, zero, scale, SpriteEffects.None, 1f); else spriteBatch.Draw(checkedBox, new Vector2(topOfList.X - 32, topOfList.Y + 30), null, Color.White, 0, zero, scale, SpriteEffects.None, 1f); if (!(players.Count >= 2 && players[1].IsReady)) spriteBatch.Draw(emptySelectBox, new Vector2(topOfList.X - 32, topOfList.Y + 100), null, Color.White, 0, zero, scale, SpriteEffects.None, 1f); else spriteBatch.Draw(checkedBox, new Vector2(topOfList.X - 32, topOfList.Y + 95), null, Color.White, 0, zero, scale, SpriteEffects.None, 1f); if (!(players.Count >= 3 && players[2].IsReady)) spriteBatch.Draw(emptySelectBox, new Vector2(topOfList.X - 32, topOfList.Y + 165), null, Color.White, 0, zero, scale, SpriteEffects.None, 1f); else spriteBatch.Draw(checkedBox, new Vector2(topOfList.X - 32, topOfList.Y + 160), null, Color.White, 0, zero, scale, SpriteEffects.None, 1f); if (!(players.Count >= 4 && players[3].IsReady)) spriteBatch.Draw(emptySelectBox, new Vector2(topOfList.X - 32, topOfList.Y + 230), null, Color.White, 0, zero, scale, SpriteEffects.None, 1f); else spriteBatch.Draw(checkedBox, new Vector2(topOfList.X - 32, topOfList.Y + 225), null, Color.White, 0, zero, scale, SpriteEffects.None, 1f); } //Chat Labels spriteBatch.DrawString(menuFont, "Chat with", new Vector2(topOfList.X + 152, topOfList.Y + 45), Color.DarkGray, 0f, zero, .6f, SpriteEffects.None, 1f); spriteBatch.DrawString(menuFont, "Chat with", new Vector2(topOfList.X + 152, topOfList.Y + 110), Color.DarkGray, 0f, zero, .6f, SpriteEffects.None, 1f); spriteBatch.DrawString(menuFont, "Chat with", new Vector2(topOfList.X + 152, topOfList.Y + 175), Color.DarkGray, 0f, zero, .6f, SpriteEffects.None, 1f); spriteBatch.DrawString(menuFont, "Chat with", new Vector2(topOfList.X + 152, topOfList.Y + 240), Color.DarkGray, 0f, zero, .6f, SpriteEffects.None, 1f); //Chat CheckBoxs Boolean chatwith = true; // change to reflect info from network, move to update and create one for each player if (!chatwith) spriteBatch.Draw(deselectBox, new Vector2(topOfList.X +218, topOfList.Y + 35), null, Color.White, 0, zero, scale, SpriteEffects.None, 1f); else spriteBatch.Draw(checkedBox, new Vector2(topOfList.X + 218, topOfList.Y + 30), null, Color.White, 0, zero, scale, SpriteEffects.None, 1f); if (!chatwith) spriteBatch.Draw(deselectBox, new Vector2(topOfList.X + 218, topOfList.Y + 100), null, Color.White, 0, zero, scale, SpriteEffects.None, 1f); else spriteBatch.Draw(checkedBox, new Vector2(topOfList.X + 218, topOfList.Y + 95), null, Color.White, 0, zero, scale, SpriteEffects.None, 1f); if (!chatwith) spriteBatch.Draw(deselectBox, new Vector2(topOfList.X + 218, topOfList.Y + 165), null, Color.White, 0, zero, scale, SpriteEffects.None, 1f); else spriteBatch.Draw(checkedBox, new Vector2(topOfList.X + 218, topOfList.Y + 160), null, Color.White, 0, zero, scale, SpriteEffects.None, 1f); if (!chatwith) spriteBatch.Draw(deselectBox, new Vector2(topOfList.X + 218, topOfList.Y + 230), null, Color.White, 0, zero, scale, SpriteEffects.None, 1f); else spriteBatch.Draw(checkedBox, new Vector2(topOfList.X + 218, topOfList.Y + 225), null, Color.White, 0, zero, scale, SpriteEffects.None, 1f); //draw player names if (players != null) { for (int g = 0; g < players.Count; g++) { spriteBatch.DrawString(menuFont, players[g].Gamertag, new Vector2(topOfList.X + 10, topOfList.Y + 10 + 65*g), Color.White, 0f, zero, .75f, SpriteEffects.None, 1f); } } } } }