+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using Microsoft.Xna.Framework.Content;\r
+using Microsoft.Xna.Framework.Input;\r
+using Microsoft.Xna.Framework;\r
+using Microsoft.Xna.Framework.Graphics;\r
+\r
+namespace CS_3505_Project_06.CS_3505\r
+{\r
+ // Everything in objects built from this class represent the critical game state\r
+ public class GameState\r
+ {\r
+ public long frameNumber;\r
+\r
+ private long checksum;\r
+ public long Checksum { get { return checksum; } }\r
+\r
+ public bool[] isGameOver;\r
+ public bool[] isTerminated;\r
+\r
+ // Since this is not a game, I'll just keep track of the user inputs as the game state.\r
+\r
+ public int[] mouseLocationX;\r
+ public int[] mouseLocationY;\r
+ public bool[] mouseButton;\r
+ public List<Keys>[] keysDown;\r
+ public int[] keypressCount;\r
+\r
+ public long elapsedTime;\r
+\r
+ /* Constructor */\r
+ public GameState()\r
+ {\r
+ frameNumber = 0;\r
+ checksum = 0;\r
+\r
+ isGameOver = new bool[4];\r
+ isTerminated = new bool[4];\r
+\r
+ mouseLocationX = new int[4];\r
+ mouseLocationY = new int[4];\r
+ mouseButton = new bool[4];\r
+ keysDown = new List<Keys>[4];\r
+ for (int i = 0; i < 4; i++)\r
+ keysDown[i] = new List<Keys>();\r
+ keypressCount = new int[4];\r
+\r
+ elapsedTime = 0;\r
+\r
+ checksum = 0;\r
+ }\r
+\r
+ /* The game engine! */\r
+ public void advanceFrame(NextInputs inputs, long milliseconds)\r
+ {\r
+ // Advance frame number\r
+ frameNumber++;\r
+\r
+ // Advance game - for the test harness, just record statistics and input states.\r
+\r
+ elapsedTime += milliseconds;\r
+\r
+ for (int player = 0; player < 4; player++)\r
+ {\r
+ if (isGameOver[player])\r
+ continue;\r
+\r
+ if (inputs.mousePressedChanged[player])\r
+ mouseButton[player] = inputs.mousePressed[player];\r
+\r
+ if (inputs.mouseLocationChanged[player])\r
+ {\r
+ mouseLocationX[player] = inputs.mouseLocationX[player];\r
+ mouseLocationY[player] = inputs.mouseLocationY[player];\r
+ }\r
+\r
+ foreach (Keys k in inputs.keysPressed[player])\r
+ if (!keysDown[player].Contains(k))\r
+ {\r
+ keysDown[player].Add(k);\r
+ keypressCount[player]++;\r
+ }\r
+\r
+ foreach (Keys k in inputs.keysReleased[player])\r
+ keysDown[player].Remove(k); \r
+\r
+ // If the mouse was pressed for a certain player, activate game over or terminated states as appropriate\r
+\r
+ if (inputs.mousePressed[player])\r
+ for (int p = 0; p < 4; p++)\r
+ {\r
+ int x = 200 * p + 10;\r
+ int y = 220;\r
+\r
+ if (mouseLocationX[player] >= x && mouseLocationY[player] >= y &&\r
+ mouseLocationX[player] < x + 25 && mouseLocationY[player] < y + 25)\r
+ {\r
+ isGameOver[p] = true;\r
+ }\r
+ y += 25;\r
+ if (mouseLocationX[player] >= x && mouseLocationY[player] >= y &&\r
+ mouseLocationX[player] < x + 25 && mouseLocationY[player] < y + 25)\r
+ {\r
+ isGameOver[p] = true;\r
+ isTerminated[p] = true;\r
+ }\r
+ }\r
+\r
+ }\r
+\r
+ // Advance the checksum.\r
+\r
+ computeChecksum();\r
+ \r
+ }\r
+\r
+ /* Just hash the values */\r
+ private long computeChecksum()\r
+ {\r
+ checksum += frameNumber;\r
+ for (int i = 0; i < 4; i++)\r
+ {\r
+ checksum = checksum + keypressCount[i];\r
+ checksum = checksum * 3 + (isGameOver[i] ? 1 : 2);\r
+ checksum = checksum * 3 + (isTerminated[i] ? 1 : 2);\r
+ foreach (Keys k in keysDown[i])\r
+ checksum = checksum * 257 + (int) k;\r
+ checksum = checksum * 25789 + mouseLocationX[i] * 259 + mouseLocationY[i] + 375;\r
+ checksum = checksum * 3 + (mouseButton[i] ? 1 : 2);\r
+\r
+ }\r
+ checksum += elapsedTime;\r
+\r
+ return checksum;\r
+ }\r
+ }\r
+\r
+ // This class encapsulates inputs from the players.\r
+ public class NextInputs\r
+ {\r
+ public List<Keys>[] keysPressed;\r
+ public List<Keys>[] keysReleased;\r
+ public int[] mouseLocationX;\r
+ public int[] mouseLocationY;\r
+ public bool[] mouseLocationChanged;\r
+ public bool[] mousePressed;\r
+ public bool[] mousePressedChanged;\r
+\r
+ public NextInputs()\r
+ {\r
+ keysPressed = new List<Keys>[4];\r
+ keysReleased = new List<Keys>[4];\r
+ mouseLocationX = new int[4];\r
+ mouseLocationY = new int[4];\r
+ mouseLocationChanged = new bool[4];\r
+ mousePressed = new bool[4];\r
+ mousePressedChanged = new bool[4];\r
+ for (int i = 0; i < 4; i++)\r
+ keysPressed[i] = new List<Keys>();\r
+ for (int i = 0; i < 4; i++)\r
+ keysReleased[i] = new List<Keys>();\r
+ }\r
+ }\r
+\r
+ public class TestHarness : IDeterministicGame\r
+ {\r
+ GameState state;\r
+ NextInputs inputs;\r
+ Object[] playerIdentifiers;\r
+ int thisPlayerID;\r
+\r
+ // Instance variables here contribute to the display, but not the game state\r
+\r
+ Texture2D crosshair;\r
+ SpriteFont font;\r
+\r
+ // Constructor\r
+\r
+ public TestHarness()\r
+ {\r
+ playerIdentifiers = new Object[4];\r
+ }\r
+\r
+ // Helper methods\r
+\r
+ private int idPlayer(Object playerIdentifier)\r
+ {\r
+ for (int i = 0; i < playerIdentifiers.Length; i++)\r
+ if (playerIdentifiers[i] == playerIdentifier)\r
+ return i;\r
+ throw new Exception("Illegal player identifier" + playerIdentifier);\r
+ }\r
+\r
+ // Implementation of the DeterministicGame interface\r
+ #region IDeterministicGame Members\r
+\r
+ public void LoadContent(ContentManager contentManager)\r
+ {\r
+ crosshair = contentManager.Load<Texture2D>("CS 3505/Crosshair");\r
+ font = contentManager.Load<SpriteFont>("CS 3505/GameFont");\r
+ }\r
+\r
+ public void UnloadContent()\r
+ {\r
+ // Nothing to do - the content manager will take care of it.\r
+ }\r
+\r
+ public Vector2 PreferredScreenSize\r
+ {\r
+ get { return new Vector2(800, 600); }\r
+ }\r
+\r
+ public int MinimumSupportedPlayers\r
+ {\r
+ get { return 4; }\r
+ }\r
+\r
+ public int MaximumSupportedPlayers\r
+ {\r
+ get { return 4; }\r
+ }\r
+\r
+ public void ResetGame(Object[] playerIdentifiers, Object thisPlayer)\r
+ {\r
+ if (playerIdentifiers.Length != 4)\r
+ throw new Exception("This game requires four players.");\r
+\r
+ // Copy the player identifiers - do not rely on the array parameter not changing.\r
+\r
+ for (int i = 0; i < 4; i++)\r
+ this.playerIdentifiers[i] = playerIdentifiers[i];\r
+\r
+ // Create new game state and inputs objects.\r
+\r
+ state = new GameState();\r
+ inputs = new NextInputs();\r
+\r
+ // Record 'this' player.\r
+\r
+ this.thisPlayerID = idPlayer(thisPlayer);\r
+ }\r
+\r
+ public long CurrentFrameNumber\r
+ {\r
+ get { return state.frameNumber; }\r
+ }\r
+\r
+ public long CurrentChecksum\r
+ {\r
+ get { return state.Checksum; }\r
+ }\r
+\r
+ public void ApplyKeyInput(Object playerIdentifier, Keys key, bool isKeyPressed)\r
+ {\r
+ int player = idPlayer(playerIdentifier);\r
+\r
+ if (isKeyPressed && !inputs.keysPressed[player].Contains(key))\r
+ inputs.keysPressed[player].Add(key);\r
+\r
+ if (!isKeyPressed && !inputs.keysReleased[player].Contains(key))\r
+ inputs.keysReleased[player].Add(key);\r
+ }\r
+\r
+ public void ApplyMouseLocationInput(Object playerIdentifier, int x, int y)\r
+ {\r
+ int player = idPlayer(playerIdentifier);\r
+ inputs.mouseLocationX[player] = x;\r
+ inputs.mouseLocationY[player] = y;\r
+ inputs.mouseLocationChanged[player] = true;\r
+ }\r
+\r
+ public void ApplyMouseButtonInput(Object playerIdentifier, bool isButtonPressed)\r
+ {\r
+ int player = idPlayer(playerIdentifier);\r
+ inputs.mousePressed[player] = isButtonPressed;\r
+ inputs.mousePressedChanged[player] = true;\r
+ }\r
+\r
+ public bool IsGameOver(Object playerIdentifier)\r
+ {\r
+ int player = idPlayer(playerIdentifier);\r
+ return state.isGameOver[player] ;\r
+ }\r
+\r
+ public bool IsTerminated(object playerIdentifier)\r
+ {\r
+ int player = idPlayer(playerIdentifier);\r
+ return state.isTerminated[player];\r
+ }\r
+\r
+ public long Update(TimeSpan elapsedTime)\r
+ {\r
+ state.advanceFrame(inputs, elapsedTime.Milliseconds); // Apply the inputs, advance game state.\r
+\r
+ inputs = new NextInputs(); // Start with inputs cleared on the next frame.\r
+\r
+ return state.frameNumber;\r
+ }\r
+\r
+ public long Draw(SpriteBatch spriteBatch)\r
+ {\r
+ centerString(spriteBatch, Color.White, "CS 3505 - Software Practice 2", 0, 800, 0);\r
+ centerString(spriteBatch, Color.White, "Test Harness", 0, 800, 25);\r
+ centerString(spriteBatch, Color.White, "Debug output", 0, 800, 50);\r
+\r
+ nameIntPair(spriteBatch, Color.White, "Frame:", state.frameNumber, 10, 150, 100);\r
+ nameHexPair(spriteBatch, Color.White, "Checksum:", state.Checksum, 215, 515, 100);\r
+ nameDecPair(spriteBatch, Color.White, "Elapsed Time:", state.elapsedTime / 1000.0f, 570, 790, 100);\r
+\r
+ printPlayer(spriteBatch, Color.Turquoise, 0, 10, 190, 170);\r
+ printPlayer(spriteBatch, Color.Wheat, 1, 210, 390, 170);\r
+ printPlayer(spriteBatch, Color.Tomato, 2, 410, 590, 170);\r
+ printPlayer(spriteBatch, Color.Violet, 3, 610, 790, 170);\r
+\r
+ if (!state.isGameOver[0])\r
+ spriteBatch.Draw(crosshair, new Vector2(state.mouseLocationX[0] - 5, state.mouseLocationY[0] - 5), Color.Turquoise);\r
+ if (!state.isGameOver[1])\r
+ spriteBatch.Draw(crosshair, new Vector2(state.mouseLocationX[1] - 5, state.mouseLocationY[1] - 5), Color.Wheat);\r
+ if (!state.isGameOver[2])\r
+ spriteBatch.Draw(crosshair, new Vector2(state.mouseLocationX[2] - 5, state.mouseLocationY[2] - 5), Color.Tomato);\r
+ if (!state.isGameOver[3])\r
+ spriteBatch.Draw(crosshair, new Vector2(state.mouseLocationX[3] - 5, state.mouseLocationY[3] - 5), Color.Violet);\r
+\r
+ spriteBatch.Draw(crosshair, new Vector2(Mouse.GetState().X - 5, Mouse.GetState().Y - 5), Color.White);\r
+\r
+ return state.frameNumber;\r
+ }\r
+\r
+ #endregion\r
+\r
+ void printPlayer(SpriteBatch spriteBatch, Color c, int player, float left, float right, float top)\r
+ {\r
+ leftJustify(spriteBatch, c, String.Format("Player {0}", player+1), left, top);\r
+ top += 10;\r
+ leftJustify(spriteBatch, c, "_________", left, top);\r
+ top += 40;\r
+ nameIntPair(spriteBatch, c, "[X] Game Over", state.isGameOver[player]?1:0, left, right, top);\r
+ top += 25;\r
+ nameIntPair(spriteBatch, c, "[X] Terminated", state.isTerminated[player] ? 1 : 0, left, right, top);\r
+ top += 40;\r
+ nameIntPair(spriteBatch, c, "Mouse X", (int)state.mouseLocationX[player], left, right, top);\r
+ top += 25;\r
+ nameIntPair(spriteBatch, c, "Mouse Y", (int)state.mouseLocationY[player], left, right, top);\r
+ top += 40;\r
+ leftJustify(spriteBatch, c, "Mouse", left, top);\r
+ rightJustify(spriteBatch, c, state.mouseButton[player]?"Pressed":"Released", right, top);\r
+ top += 40;\r
+ nameIntPair(spriteBatch, c, "Key count", (int)state.keypressCount[player], left, right, top);\r
+ top += 25;\r
+ leftJustify(spriteBatch, c, "Keys", left, top);\r
+ if (state.keysDown[player].Count == 0)\r
+ rightJustify(spriteBatch, c, "None", right, top);\r
+ else\r
+ foreach (Keys k in state.keysDown[player])\r
+ {\r
+ rightJustify(spriteBatch, c, k.ToString(), right, top);\r
+ top += 25;\r
+ }\r
+\r
+ }\r
+\r
+ void centerString(SpriteBatch spriteBatch, Color c, String s, float left, float right, float top)\r
+ {\r
+ Vector2 v = font.MeasureString(s);\r
+ float x = left + (right-left - v.X) / 2;\r
+ float y = top;\r
+ spriteBatch.DrawString(font, s, new Vector2(x, y), c);\r
+ }\r
+\r
+ void centerString(SpriteBatch spriteBatch, Color c, String s, Rectangle r)\r
+ {\r
+ Vector2 v = font.MeasureString(s);\r
+ float x = r.Left + (r.Width - v.X) / 2;\r
+ float y = r.Top + (r.Height - v.Y) / 2;\r
+ spriteBatch.DrawString(font, s, new Vector2(x, y), c);\r
+ }\r
+\r
+ void leftJustify(SpriteBatch spriteBatch, Color c, String s, float left, float top)\r
+ {\r
+ float x = left;\r
+ float y = top;\r
+ spriteBatch.DrawString(font, s, new Vector2(x, y), c);\r
+ }\r
+\r
+ void rightJustify(SpriteBatch spriteBatch, Color c, String s, float right, float top)\r
+ {\r
+ Vector2 v = font.MeasureString(s);\r
+ float x = right - v.X;\r
+ float y = top;\r
+ spriteBatch.DrawString(font, s, new Vector2(x, y), c);\r
+ }\r
+\r
+ void nameDecPair(SpriteBatch spriteBatch, Color c, String name, float number, float left, float right, float top)\r
+ {\r
+ String num = String.Format("{0:.00}", number);\r
+ leftJustify(spriteBatch, c, name, left, top);\r
+ rightJustify(spriteBatch, c, num, right, top);\r
+ }\r
+\r
+ void nameIntPair(SpriteBatch spriteBatch, Color c, String name, long number, float left, float right, float top)\r
+ {\r
+ String num = String.Format("{0}", number);\r
+ leftJustify(spriteBatch, c, name, left, top);\r
+ rightJustify(spriteBatch, c, num, right, top);\r
+ }\r
+\r
+ void nameHexPair(SpriteBatch spriteBatch, Color c, String name, long number, float left, float right, float top)\r
+ {\r
+ String num = String.Format("{0:x}", number);\r
+ leftJustify(spriteBatch, c, name, left, top);\r
+ rightJustify(spriteBatch, c, num, right, top);\r
+ }\r
+ }\r
+}\r