using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; namespace CarFire { /// /// Container class for the whole state of the game. /// public class GameState { #region Public Properties public long FrameNumber { get { return mFrameNumber; } } public long Checksum { get { return mChecksum; } } public int NumberOfPlayers { get { return mNumberOfPlayers; } } public Map Map; public List Entities = new List(); public IPlayer[] mCharacters = new IPlayer[4]; public Display mDisplay; #endregion #region Public Methods /// /// Construct a game state container with the number of players. /// /// Number of players. public GameState(int numPlayers) { mNumberOfPlayers = numPlayers; mFrameNumber = 0; mIsGameOver = new bool[numPlayers]; mIsTerminated = new bool[numPlayers]; mMouseLocation = new Point[numPlayers]; mMouseButton = new bool[numPlayers]; mKeysDown = new List[numPlayers]; for (int i = 0; i < numPlayers; i++) mKeysDown[i] = new List(); mKeypressCount = new int[numPlayers]; mElapsedTime = 0; mChecksum = 0; } /// /// Should be called by the Game class to advance the state /// to the next frame. /// /// The inputs that occurred to be /// applied this coming frame. /// Milliseconds; used for the checksum. public void AdvanceFrame(NextInputs inputs, long milliseconds) { mFrameNumber++; mElapsedTime += milliseconds; for (int player = 0; player < NumberOfPlayers; player++) { if (inputs.IsMousePressedChanged[player]) { mMouseButton[player] = inputs.MousePressed[player]; } if (inputs.IsMouseLocationChanged[player]) { mMouseLocation[player] = inputs.MouseLocation[player]; } foreach (Keys k in inputs.KeysPressed[player]) { if (!mKeysDown[player].Contains(k)) { mKeysDown[player].Add(k); mKeypressCount[player]++; } } foreach (Keys k in inputs.KeysReleased[player]) mKeysDown[player].Remove(k); } ComputeChecksum(); } /// /// Get the mouse location for a player. /// /// Player Number. /// Mouse location. public Point GetMouseLocation(int playerNum) { return mMouseLocation[playerNum]; } /// /// Get the mouse button state for a player. /// /// Player number. /// Mouse button state.. public bool GetMouseButton(int playerNum) { return mMouseButton[playerNum]; } /// /// Get the keyboard state for a player. /// /// Player number. /// Keyboard state. public List GetKeysDown(int playerNum) { return mKeysDown[playerNum]; } #endregion #region Private Methods // Calculates a checksum for debugging network synchronization issues. long ComputeChecksum() { mChecksum += FrameNumber; for (int i = 0; i < NumberOfPlayers; i++) { mChecksum = mChecksum + mKeypressCount[i]; mChecksum = mChecksum * 3 + (mIsGameOver[i] ? 1 : 2); mChecksum = mChecksum * 3 + (mIsTerminated[i] ? 1 : 2); foreach (Keys k in mKeysDown[i]) mChecksum = mChecksum * 257 + (int)k; mChecksum = mChecksum * 25789 + mMouseLocation[i].X * 259 + mMouseLocation[i].Y + 375; mChecksum = mChecksum * 3 + (mMouseButton[i] ? 1 : 2); } mChecksum += mElapsedTime; return mChecksum; } #endregion #region Private Variables int mNumberOfPlayers; public Point[] mMouseLocation; public bool[] mMouseButton; public List[] mKeysDown; long mFrameNumber; bool[] mIsGameOver; bool[] mIsTerminated; int[] mKeypressCount; long mElapsedTime; long mChecksum; #endregion } /// /// Container class for all the inputs for a single frame. /// public class NextInputs { public List[] KeysPressed; public List[] KeysReleased; public Point[] MouseLocation; public bool[] IsMouseLocationChanged; public bool[] MousePressed; public bool[] IsMousePressedChanged; public NextInputs(int numPlayers) { KeysPressed = new List[numPlayers]; KeysReleased = new List[numPlayers]; IsMouseLocationChanged = new bool[numPlayers]; MousePressed = new bool[numPlayers]; IsMousePressedChanged = new bool[numPlayers]; for (int i = 0; i < numPlayers; i++) KeysPressed[i] = new List(); for (int i = 0; i < numPlayers; i++) KeysReleased[i] = new List(); } } /// /// The big kahuna. /// public class Game : IDeterministicGame { #region Public Properties /// /// Get the content manager associated with this game. /// public ContentManager ContentManager { get { return mContentManager; } } /// /// Get the state. /// public GameState State; public bool[,] Grid { get { bool[,] grid = State.Map.Grid; foreach (IEntity entity in State.Entities) { Point coordinates = entity.Coordinates; grid[coordinates.X, coordinates.Y] = true; } return grid; } } #endregion #region Public Methods public bool IsCellOpen(Point point) { if (!State.Map.IsCellOpen(point)) return false; foreach (IEntity entity in State.Entities) { if (entity.Coordinates == point) return false; } return true; } public Game() { } public void LoadContent(ContentManager contentManager) { mContentManager = contentManager; menu = mContentManager.Load("menuFont"); } public void UnloadContent() { } private int GetPlayerNumber(Object playerIdentifier) { for (int i = 0; i < mPlayerIdentifiers.Length; i++) { if (mPlayerIdentifiers[i] == playerIdentifier) return i; } throw new Exception("Illegal player identifier" + playerIdentifier); } public Vector2 PreferredScreenSize { get { return new Vector2(800, 600); } } public int MinimumSupportedPlayers { get { return 1; } } public int MaximumSupportedPlayers { get { return 4; } } public void ResetGame(object[] playerIdentifiers, object thisPlayer) { int numPlayers = playerIdentifiers.Count(); mPlayerIdentifiers = new object[numPlayers]; for (int i = 0; i < numPlayers; i++) mPlayerIdentifiers[i] = playerIdentifiers[i]; mThisPlayerID = GetPlayerNumber(thisPlayer); State = new GameState(numPlayers); mInputs = new NextInputs(numPlayers); State.mDisplay = new Display(this); State.mDisplay.LoadContent(mContentManager); State.Map = mContentManager.Load("Maps/stable"); State.Map.Game = this; State.Entities = State.Map.GetAllEntities(); Map.DefaultTile = mContentManager.Load("default"); /* mPlayers.Clear(); for (int i = 0; i < PlayerIdentifiers.Length; i++) { Human player = new Human(mMap, ""); mPlayers.Add(player); mDisplay.AddCharacters(player); mPlayers.Add(player); mDisplay.AddCharacters(player); } this.playerIdentifiers = PlayerIdentifiers; for (int i = 0; i < mPlayers.Count; i++) { Point starting = mMap.GetStartingPositionForPlayer(i + 1); mPlayers[i].Spawn(new Vector2(starting.X, starting.Y)); } */ } public long CurrentFrameNumber { get { return State.FrameNumber; } } public long CurrentChecksum { get { return 0; } } public void ApplyKeyInput(object playerIdentifier, Keys key, bool isKeyPressed) { //code from Prof Jensen's TestHarness int player = GetPlayerNumber(playerIdentifier); if (isKeyPressed && !mInputs.KeysPressed[player].Contains(key)) mInputs.KeysPressed[player].Add(key); if (!isKeyPressed && !mInputs.KeysReleased[player].Contains(key)) mInputs.KeysReleased[player].Add(key); } public void ApplyMouseLocationInput(object playerIdentifier, int x, int y) { } public void ApplyMouseButtonInput(object playerIdentifier, bool isButtonPressed) { } public bool IsGameOver(object playerIdentifier) { return false; } public bool IsTerminated(object playerIdentifier) { return false; } public long Update(TimeSpan elapsedTime) { State.AdvanceFrame(mInputs, elapsedTime.Milliseconds); // Apply the inputs, advance game state. State.mDisplay.Update(elapsedTime, State, mThisPlayerID); State.Entities.ForEach(delegate(IEntity e) { e.Update(elapsedTime); }); mInputs = new NextInputs(State.NumberOfPlayers); // Start with inputs cleared on the next frame. //mDisplay.Update(elapsedTime); return State.FrameNumber; } public long Draw(SpriteBatch spriteBatch) { bool allCharactersSelected = true; for (int i = 0; i < State.NumberOfPlayers; i++) { //If player has not selected a player yet let them select one. if (State.mCharacters[i] == null) { allCharactersSelected = false; if (State.GetKeysDown(i).Contains(Keys.Enter)) { State.mCharacters[i] = new Ranged(this, "", State.Map.GetStartingPositionForPlayer(i + 1), i); State.mCharacters[i].LoadContent(mContentManager); } } } if (allCharactersSelected) { State.mDisplay.Draw(spriteBatch); } else { spriteBatch.GraphicsDevice.Clear(Color.Black); spriteBatch.DrawString(menu, "Press Enter To Select A Character", new Vector2(30, 30), Color.RosyBrown); } return CurrentFrameNumber; } #endregion #region Private Variables SpriteFont menu; ContentManager mContentManager; NextInputs mInputs; Object[] mPlayerIdentifiers; int mThisPlayerID; #endregion } }