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