#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.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Audio; using System.IO.IsolatedStorage; using System.IO; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input.Touch; //using Microsoft.Devices.Sensors; using GameStateManagement; using Microsoft.Xna.Framework.Net; #endregion namespace CatapultGame { class GameplayScreen : GameScreen { #region Fields enum MessageType : byte { NewGame = 1, CatapultFiring = 2, CatapultAiming = 3, UpdateEnvironment = 4, } internal NetworkSession NetworkSession { get; private set; } PacketReader packetReader = new PacketReader (); PacketWriter packetWriter = new PacketWriter (); internal bool IsNetworking { get; private set; } // Texture Members Texture2D foregroundTexture; Texture2D cloud1Texture; Texture2D cloud2Texture; Texture2D mountainTexture; Texture2D skyTexture; Texture2D hudBackgroundTexture; Texture2D ammoTypeTexture; Texture2D windArrowTexture; Texture2D defeatTexture; Texture2D victoryTexture; SpriteFont hudFont; // Rendering members Vector2 cloud1Position; Vector2 cloud2Position; Vector2 playerOneHUDPosition; Vector2 computerHUDPosition; Vector2 windArrowPosition; // Gameplay members Human playerOne; Human playerTwo; Vector2 wind; bool changeTurn; bool isFirstPlayerTurn; bool gameOver; Random random; const int minWind = 0; const int maxWind = 10; // Helper members bool isDragging; #endregion #region Initialization public GameplayScreen () { EnabledGestures = GestureType.FreeDrag | GestureType.DragComplete | GestureType.Tap; random = new Random (); } #endregion #region Content Loading/Unloading /// /// Loads the game assets and initializes "players" /// public override void LoadContent () { base.LoadContent (); // Start the game Start (); } public void LoadAssets () { NetworkSession = ScreenManager.Game.Services.GetService (typeof(NetworkSession)) as NetworkSession; IsNetworking = NetworkSession != null; // Load textures foregroundTexture = Load ("Textures/Backgrounds/gameplay_screen"); cloud1Texture = Load ("Textures/Backgrounds/cloud1"); cloud2Texture = Load ("Textures/Backgrounds/cloud2"); mountainTexture = Load ("Textures/Backgrounds/mountain"); skyTexture = Load ("Textures/Backgrounds/sky"); defeatTexture = Load ("Textures/Backgrounds/defeat"); victoryTexture = Load ("Textures/Backgrounds/victory"); hudBackgroundTexture = Load ("Textures/HUD/hudBackground"); windArrowTexture = Load ("Textures/HUD/windArrow"); ammoTypeTexture = Load ("Textures/HUD/ammoType"); // Load font hudFont = Load ("Fonts/HUDFont"); // Define initial cloud position cloud1Position = new Vector2 (224 - cloud1Texture.Width, 32); cloud2Position = new Vector2 (64, 90); // Define initial HUD positions playerOneHUDPosition = new Vector2 (7, 7); computerHUDPosition = new Vector2 (613, 7); windArrowPosition = new Vector2 (345, 46); // Initialize human & other players if (IsNetworking) { if (NetworkSession.RemoteGamers.Count > 0) { if (NetworkSession.IsHost) { playerOne = new Human (ScreenManager.Game, ScreenManager.SpriteBatch, PlayerSide.Left); playerOne.Initialize (); playerOne.Name = NetworkSession.LocalGamers [0].Gamertag + " (host)"; playerTwo = new Human (ScreenManager.Game, ScreenManager.SpriteBatch, PlayerSide.Right); playerTwo.Initialize (); playerTwo.Name = NetworkSession.RemoteGamers [0].Gamertag; } else { playerOne = new Human (ScreenManager.Game, ScreenManager.SpriteBatch, PlayerSide.Left); playerOne.Initialize (); playerOne.Name = NetworkSession.RemoteGamers [0].Gamertag + " (host)"; playerTwo = new Human (ScreenManager.Game, ScreenManager.SpriteBatch, PlayerSide.Right); playerTwo.Initialize (); playerTwo.Name = NetworkSession.LocalGamers [0].Gamertag; } } else { playerOne = new Human (ScreenManager.Game, ScreenManager.SpriteBatch, PlayerSide.Left); playerOne.Initialize (); playerOne.Name = NetworkSession.LocalGamers [0].Gamertag + " (host)"; playerTwo = new Human (ScreenManager.Game, ScreenManager.SpriteBatch, PlayerSide.Right); playerTwo.Initialize (); playerTwo.Name = "Player 2"; IsNetworking = false; NetworkSession.Dispose(); NetworkSession = null; } } else { playerOne = new Human (ScreenManager.Game, ScreenManager.SpriteBatch, PlayerSide.Left); playerOne.Initialize (); playerOne.Name = "Player 1"; playerTwo = new AI (ScreenManager.Game, ScreenManager.SpriteBatch); playerTwo.Initialize (); playerTwo.Name = "Player 2"; } // Identify enemies playerOne.Enemy = playerTwo; playerTwo.Enemy = playerOne; } #endregion #region Update /// /// Runs one frame of update for the game. /// /// Provides a snapshot of timing values. public override void Update (GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen) { float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds; // Check it one of the players reached 5 and stop the game if ((playerOne.Catapult.GameOver || playerTwo.Catapult.GameOver) && (gameOver == false)) { gameOver = true; if (IsNetworking) { if (NetworkSession.IsHost) { if (playerOne.Score > playerTwo.Score) { AudioManager.PlaySound ("gameOver_Win"); } else { AudioManager.PlaySound ("gameOver_Lose"); } } else { if (playerOne.Score > playerTwo.Score) { AudioManager.PlaySound ("gameOver_Lose"); } else { AudioManager.PlaySound ("gameOver_Win"); } } } else { if (playerOne.Score > playerTwo.Score) { AudioManager.PlaySound ("gameOver_Win"); } else { AudioManager.PlaySound ("gameOver_Lose"); } } return; } // If Reset flag raised and both catapults are not animating - // active catapult finished the cycle, new turn! if ((playerOne.Catapult.CurrentState == CatapultState.Reset || playerTwo.Catapult.CurrentState == CatapultState.Reset) && !(playerOne.Catapult.AnimationRunning || playerTwo.Catapult.AnimationRunning)) { changeTurn = true; if (playerOne.IsActive == true) { //Last turn was a human turn? playerOne.IsActive = false; playerTwo.IsActive = true; isFirstPlayerTurn = false; playerOne.Catapult.CurrentState = CatapultState.Idle; if (playerTwo.IsAI) playerTwo.Catapult.CurrentState = CatapultState.Aiming; else playerTwo.Catapult.CurrentState = CatapultState.Idle; } else { //It was an AI turn playerOne.IsActive = true; playerTwo.IsActive = false; isFirstPlayerTurn = true; playerTwo.Catapult.CurrentState = CatapultState.Idle; playerOne.Catapult.CurrentState = CatapultState.Idle; } } if (changeTurn) { // Update wind wind = new Vector2 (random.Next (-1, 2), random.Next (minWind, maxWind + 1)); // Set new wind value to the players and playerOne.Catapult.Wind = playerTwo.Catapult.Wind = wind.X > 0 ? wind.Y : -wind.Y; changeTurn = false; } // Update the players playerOne.Update (gameTime); playerTwo.Update (gameTime); // Updates the clouds position UpdateClouds (elapsed); UpdateNetworkSession (); base.Update (gameTime, otherScreenHasFocus, coveredByOtherScreen); } #endregion #region Draw /// /// Draw the game world, effects, and HUD /// /// The elapsed time since last Draw public override void Draw (GameTime gameTime) { ScreenManager.SpriteBatch.Begin (); // Render all parts of the screen DrawBackground (); DrawComputer (gameTime); DrawPlayer (gameTime); DrawHud (); ScreenManager.SpriteBatch.End (); } #endregion #region Input /// /// Input helper method provided by GameScreen. Packages up the various input /// values for ease of use. /// /// The state of the gamepads public override void HandleInput (InputState input) { if (input == null) throw new ArgumentNullException ("input"); if (gameOver) { if (input.IsPauseGame (null)) { FinishCurrentGame (); } if (input.MouseGesture.HasFlag(MouseGestureType.LeftClick)) FinishCurrentGame(); foreach (GestureSample gestureSample in input.Gestures) { if (gestureSample.GestureType == GestureType.Tap) { FinishCurrentGame (); } } return; } if (NetworkSession != null) { if ((isFirstPlayerTurn && !NetworkSession.IsHost) || (!isFirstPlayerTurn && NetworkSession.IsHost)) return; } if (input.IsPauseGame (null)) { PauseCurrentGame (); } else if (isFirstPlayerTurn && (playerOne.Catapult.CurrentState == CatapultState.Idle || playerOne.Catapult.CurrentState == CatapultState.Aiming)) { // First we try with mouse input playerOne.HandleInput (input); isDragging = playerOne.isDragging; // Read all available gestures foreach (GestureSample gestureSample in input.Gestures) { if (gestureSample.GestureType == GestureType.FreeDrag) isDragging = true; else if (gestureSample.GestureType == GestureType.DragComplete) isDragging = false; playerOne.HandleInput (gestureSample); } } else if (!isFirstPlayerTurn && (playerTwo.Catapult.CurrentState == CatapultState.Idle || playerTwo.Catapult.CurrentState == CatapultState.Aiming)) { // First we try with mouse input playerTwo.HandleInput (input); isDragging = playerTwo.isDragging; // Read all available gestures foreach (GestureSample gestureSample in input.Gestures) { if (gestureSample.GestureType == GestureType.FreeDrag) isDragging = true; else if (gestureSample.GestureType == GestureType.DragComplete) isDragging = false; playerTwo.HandleInput (gestureSample); } } } Vector3 catapultInfoVector = Vector3.Zero; void UpdateNetworkSession () { if (NetworkSession == null) return; if (NetworkSession.IsHost) { packetWriter.Write((int)MessageType.UpdateEnvironment); packetWriter.Write(wind); packetWriter.Write(cloud1Position); packetWriter.Write(cloud2Position); // Update our locally controlled tanks, and send their // latest position data to everyone in the session. foreach (LocalNetworkGamer gamer in NetworkSession.LocalGamers) { gamer.SendData(packetWriter, SendDataOptions.ReliableInOrder); } } if (playerOne.Catapult.CurrentState == CatapultState.Aiming) { SendCatapultInfo(MessageType.CatapultAiming, playerOne); } if (playerOne.Catapult.CurrentState == CatapultState.Firing) { SendCatapultInfo(MessageType.CatapultFiring, playerOne); } if (playerTwo.Catapult.CurrentState == CatapultState.Aiming) { SendCatapultInfo(MessageType.CatapultAiming, playerTwo); } if (playerTwo.Catapult.CurrentState == CatapultState.Firing) { SendCatapultInfo(MessageType.CatapultFiring, playerTwo); } // Pump the underlying session object. NetworkSession.Update (); // Make sure the session has not ended. if (NetworkSession == null) return; // Read any packets foreach (LocalNetworkGamer gamer in NetworkSession.LocalGamers) { ReadIncomingPackets (gamer); } } void SendCatapultInfo (MessageType messageType, Human player) { packetWriter.Write((int)messageType); catapultInfoVector.X = player.Catapult.ShotStrength; catapultInfoVector.Y = player.Catapult.ShotVelocity; catapultInfoVector.Z = player.ArrowScale; packetWriter.Write(catapultInfoVector); // Update our locally controlled catapults, and send their // latest position data to everyone in the session. foreach (LocalNetworkGamer gamer in NetworkSession.LocalGamers) { gamer.SendData(packetWriter, SendDataOptions.ReliableInOrder); } } /// /// Helper for reading incoming network packets. /// void ReadIncomingPackets (LocalNetworkGamer gamer) { // Keep reading as long as incoming packets are available. while (gamer.IsDataAvailable) { NetworkGamer sender; // Read a single packet from the network. gamer.ReceiveData (packetReader, out sender); // Discard packets sent by local gamers: we already know their state! if (sender.IsLocal) continue; MessageType msgType = (MessageType)packetReader.ReadInt32 (); switch (msgType) { case MessageType.NewGame: //ReceiveNewNetworkedGame(); break; case MessageType.CatapultAiming: if (isFirstPlayerTurn && !NetworkSession.IsHost) { playerOne.Catapult.CurrentState = CatapultState.Aiming; playerOne.isDragging = true; catapultInfoVector = packetReader.ReadVector3(); playerOne.Catapult.ShotStrength = catapultInfoVector.X; playerOne.Catapult.ShotVelocity = catapultInfoVector.Y; playerOne.ArrowScale = catapultInfoVector.Z; } if (!isFirstPlayerTurn && NetworkSession.IsHost) { playerTwo.Catapult.CurrentState = CatapultState.Aiming; playerTwo.isDragging = true; catapultInfoVector = packetReader.ReadVector3(); playerTwo.Catapult.ShotStrength = catapultInfoVector.X; playerTwo.Catapult.ShotVelocity = catapultInfoVector.Y; playerTwo.ArrowScale = catapultInfoVector.Z; } break; case MessageType.CatapultFiring: if (isFirstPlayerTurn && !NetworkSession.IsHost) { catapultInfoVector = packetReader.ReadVector3(); playerOne.Catapult.Fire (catapultInfoVector.Y); playerOne.Catapult.CurrentState = CatapultState.Firing; playerOne.ResetDragState(); } if (!isFirstPlayerTurn && NetworkSession.IsHost) { catapultInfoVector = packetReader.ReadVector3(); playerTwo.Catapult.Fire (catapultInfoVector.Y); playerTwo.Catapult.CurrentState = CatapultState.Firing; playerTwo.ResetDragState(); } break; case MessageType.UpdateEnvironment: wind = packetReader.ReadVector2(); cloud1Position = packetReader.ReadVector2(); cloud2Position = packetReader.ReadVector2(); // Set new wind value to the players and playerOne.Catapult.Wind = playerTwo.Catapult.Wind = wind.X > 0 ? wind.Y : -wind.Y; break; } } } #endregion #region Update Helpers private void UpdateClouds (float elapsedTime) { // Move the clouds according to the wind int windDirection = wind.X > 0 ? 1 : -1; cloud1Position += new Vector2 (24.0f, 0.0f) * elapsedTime * windDirection * wind.Y; if (cloud1Position.X > ScreenManager.GraphicsDevice.Viewport.Width) cloud1Position.X = -cloud1Texture.Width * 2.0f; else if (cloud1Position.X < -cloud1Texture.Width * 2.0f) cloud1Position.X = ScreenManager.GraphicsDevice.Viewport.Width; cloud2Position += new Vector2 (16.0f, 0.0f) * elapsedTime * windDirection * wind.Y; if (cloud2Position.X > ScreenManager.GraphicsDevice.Viewport.Width) cloud2Position.X = -cloud2Texture.Width * 2.0f; else if (cloud2Position.X < -cloud2Texture.Width * 2.0f) cloud2Position.X = ScreenManager.GraphicsDevice.Viewport.Width; } #endregion #region Draw Helpers /// /// Draws the player's catapult /// void DrawPlayer (GameTime gameTime) { if (!gameOver) playerOne.Draw (gameTime); } /// /// Draws the AI's catapult /// void DrawComputer (GameTime gameTime) { if (!gameOver) playerTwo.Draw (gameTime); } /// /// Draw the sky, clouds, mountains, etc. /// private void DrawBackground () { // Clear the background ScreenManager.Game.GraphicsDevice.Clear (Color.White); // Draw the Sky ScreenManager.SpriteBatch.Draw (skyTexture, Vector2.Zero, Color.White); // Draw Cloud #1 ScreenManager.SpriteBatch.Draw (cloud1Texture, cloud1Position, Color.White); // Draw the Mountain ScreenManager.SpriteBatch.Draw (mountainTexture, Vector2.Zero, Color.White); // Draw Cloud #2 ScreenManager.SpriteBatch.Draw (cloud2Texture, cloud2Position, Color.White); // Draw the Castle, trees, and foreground ScreenManager.SpriteBatch.Draw (foregroundTexture, Vector2.Zero, Color.White); } /// /// Draw the HUD, which consists of the score elements and the GAME OVER tag. /// void DrawHud () { if (gameOver) { Texture2D texture; if (IsNetworking) { if (NetworkSession.IsHost) { if (playerOne.Score > playerTwo.Score) { texture = victoryTexture; } else { texture = defeatTexture; } } else { if (playerOne.Score > playerTwo.Score) { texture = defeatTexture; } else { texture = victoryTexture; } } } else { if (playerOne.Score > playerTwo.Score) { texture = victoryTexture; } else { texture = defeatTexture; } } ScreenManager.SpriteBatch.Draw (texture, new Vector2 (ScreenManager.Game.GraphicsDevice.Viewport.Width / 2 - texture.Width / 2, ScreenManager.Game.GraphicsDevice.Viewport.Height / 2 - texture.Height / 2), Color.White); } else { // Draw Player Hud ScreenManager.SpriteBatch.Draw (hudBackgroundTexture, playerOneHUDPosition, Color.White); ScreenManager.SpriteBatch.Draw (ammoTypeTexture, playerOneHUDPosition + new Vector2 (33, 35), Color.White); DrawString (hudFont, playerOne.Score.ToString (), playerOneHUDPosition + new Vector2 (123, 35), Color.White); DrawString (hudFont, playerOne.Name, playerOneHUDPosition + new Vector2 (40, 1), Color.Blue); // Draw Computer Hud ScreenManager.SpriteBatch.Draw (hudBackgroundTexture, computerHUDPosition, Color.White); ScreenManager.SpriteBatch.Draw (ammoTypeTexture, computerHUDPosition + new Vector2 (33, 35), Color.White); DrawString (hudFont, playerTwo.Score.ToString (), computerHUDPosition + new Vector2 (123, 35), Color.White); DrawString (hudFont, playerTwo.Name, computerHUDPosition + new Vector2 (40, 1), Color.Red); // Draw Wind direction string text = "WIND"; Vector2 size = hudFont.MeasureString (text); Vector2 windarrowScale = new Vector2 (wind.Y / 10, 1); ScreenManager.SpriteBatch.Draw (windArrowTexture, windArrowPosition, null, Color.White, 0, Vector2.Zero, windarrowScale, wind.X > 0 ? SpriteEffects.None : SpriteEffects.FlipHorizontally, 0); DrawString (hudFont, text, windArrowPosition - new Vector2 (0, size.Y), Color.Black); if (wind.Y == 0) { text = "NONE"; DrawString (hudFont, text, windArrowPosition, Color.Black); } if (IsNetworking) { if (isFirstPlayerTurn) { if (NetworkSession.IsHost) { // Prepare player one prompt message text = !isDragging ? "Drag Anywhere to Fire" : "Release to Fire!"; } else { text = "Waiting for " + playerOne.Name; } } else { if (NetworkSession.IsHost) { // Prepare player one prompt message text = "Waiting for " + playerTwo.Name; } else { text = !isDragging ? "Drag Anywhere to Fire" : "Release to Fire!"; } } } else { if (isFirstPlayerTurn) { // Prepare player one prompt message text = !isDragging ? "Drag Anywhere to Fire" : "Release to Fire!"; } else { // Prepare other player message text = "I'll get you yet!"; } } size = hudFont.MeasureString (text); DrawString (hudFont, text, new Vector2 (ScreenManager.GraphicsDevice.Viewport.Width / 2 - size.X / 2, ScreenManager.GraphicsDevice.Viewport.Height - size.Y), Color.Green); } } /// /// A simple helper to draw shadowed text. /// void DrawString (SpriteFont font, string text, Vector2 position, Color color) { ScreenManager.SpriteBatch.DrawString (font, text, new Vector2 (position.X + 1, position.Y + 1), Color.Black); ScreenManager.SpriteBatch.DrawString (font, text, position, color); } /// /// A simple helper to draw shadowed text. /// void DrawString (SpriteFont font, string text, Vector2 position, Color color, float fontScale) { ScreenManager.SpriteBatch.DrawString (font, text, new Vector2 (position.X + 1, position.Y + 1), Color.Black, 0, new Vector2 (0, font.LineSpacing / 2), fontScale, SpriteEffects.None, 0); ScreenManager.SpriteBatch.DrawString (font, text, position, color, 0, new Vector2 (0, font.LineSpacing / 2), fontScale, SpriteEffects.None, 0); } #endregion #region Input Helpers /// /// Finish the current game /// private void FinishCurrentGame () { ExitScreen (); } /// /// Pause the current game /// private void PauseCurrentGame () { var pauseMenuBackground = new BackgroundScreen (); if (isDragging) { isDragging = false; playerOne.Catapult.CurrentState = CatapultState.Idle; } ScreenManager.AddScreen (pauseMenuBackground, null); ScreenManager.AddScreen (new PauseScreen (pauseMenuBackground, playerOne, playerTwo), null); } #endregion #region Gameplay Helpers /// /// Starts a new game session, setting all game states to initial values. /// void Start () { // Set initial wind direction wind = Vector2.Zero; isFirstPlayerTurn = false; changeTurn = true; playerTwo.Catapult.CurrentState = CatapultState.Reset; } #endregion } }