2 using System.Collections.Generic;
5 using Microsoft.Xna.Framework.Content;
6 using Microsoft.Xna.Framework.Input;
7 using Microsoft.Xna.Framework;
8 using Microsoft.Xna.Framework.Graphics;
10 namespace CS_3505_Project_06.CS_3505
12 // Everything in objects built from this class represent the critical game state
13 public class GameState
15 public long frameNumber;
17 private long checksum;
18 public long Checksum { get { return checksum; } }
20 public bool[] isGameOver;
21 public bool[] isTerminated;
23 // Since this is not a game, I'll just keep track of the user inputs as the game state.
25 public int[] mouseLocationX;
26 public int[] mouseLocationY;
27 public bool[] mouseButton;
28 public List<Keys>[] keysDown;
29 public int[] keypressCount;
31 public long elapsedTime;
39 isGameOver = new bool[4];
40 isTerminated = new bool[4];
42 mouseLocationX = new int[4];
43 mouseLocationY = new int[4];
44 mouseButton = new bool[4];
45 keysDown = new List<Keys>[4];
46 for (int i = 0; i < 4; i++)
47 keysDown[i] = new List<Keys>();
48 keypressCount = new int[4];
55 /* The game engine! */
56 public void advanceFrame(NextInputs inputs, long milliseconds)
58 // Advance frame number
61 // Advance game - for the test harness, just record statistics and input states.
63 elapsedTime += milliseconds;
65 for (int player = 0; player < 4; player++)
67 if (isGameOver[player])
70 if (inputs.mousePressedChanged[player])
71 mouseButton[player] = inputs.mousePressed[player];
73 if (inputs.mouseLocationChanged[player])
75 mouseLocationX[player] = inputs.mouseLocationX[player];
76 mouseLocationY[player] = inputs.mouseLocationY[player];
79 foreach (Keys k in inputs.keysPressed[player])
80 if (!keysDown[player].Contains(k))
82 keysDown[player].Add(k);
83 keypressCount[player]++;
86 foreach (Keys k in inputs.keysReleased[player])
87 keysDown[player].Remove(k);
89 // If the mouse was pressed for a certain player, activate game over or terminated states as appropriate
91 if (inputs.mousePressed[player])
92 for (int p = 0; p < 4; p++)
97 if (mouseLocationX[player] >= x && mouseLocationY[player] >= y &&
98 mouseLocationX[player] < x + 25 && mouseLocationY[player] < y + 25)
100 isGameOver[p] = true;
103 if (mouseLocationX[player] >= x && mouseLocationY[player] >= y &&
104 mouseLocationX[player] < x + 25 && mouseLocationY[player] < y + 25)
106 isGameOver[p] = true;
107 isTerminated[p] = true;
113 // Advance the checksum.
119 /* Just hash the values */
120 private long computeChecksum()
122 checksum += frameNumber;
123 for (int i = 0; i < 4; i++)
125 checksum = checksum + keypressCount[i];
126 checksum = checksum * 3 + (isGameOver[i] ? 1 : 2);
127 checksum = checksum * 3 + (isTerminated[i] ? 1 : 2);
128 foreach (Keys k in keysDown[i])
129 checksum = checksum * 257 + (int) k;
130 checksum = checksum * 25789 + mouseLocationX[i] * 259 + mouseLocationY[i] + 375;
131 checksum = checksum * 3 + (mouseButton[i] ? 1 : 2);
134 checksum += elapsedTime;
140 // This class encapsulates inputs from the players.
141 public class NextInputs
143 public List<Keys>[] keysPressed;
144 public List<Keys>[] keysReleased;
145 public int[] mouseLocationX;
146 public int[] mouseLocationY;
147 public bool[] mouseLocationChanged;
148 public bool[] mousePressed;
149 public bool[] mousePressedChanged;
153 keysPressed = new List<Keys>[4];
154 keysReleased = new List<Keys>[4];
155 mouseLocationX = new int[4];
156 mouseLocationY = new int[4];
157 mouseLocationChanged = new bool[4];
158 mousePressed = new bool[4];
159 mousePressedChanged = new bool[4];
160 for (int i = 0; i < 4; i++)
161 keysPressed[i] = new List<Keys>();
162 for (int i = 0; i < 4; i++)
163 keysReleased[i] = new List<Keys>();
167 public class TestHarness : IDeterministicGame
171 Object[] playerIdentifiers;
174 // Instance variables here contribute to the display, but not the game state
183 playerIdentifiers = new Object[4];
188 private int idPlayer(Object playerIdentifier)
190 for (int i = 0; i < playerIdentifiers.Length; i++)
191 if (playerIdentifiers[i] == playerIdentifier)
193 throw new Exception("Illegal player identifier" + playerIdentifier);
196 // Implementation of the DeterministicGame interface
197 #region IDeterministicGame Members
199 public void LoadContent(ContentManager contentManager)
201 crosshair = contentManager.Load<Texture2D>("CS 3505/Crosshair");
202 font = contentManager.Load<SpriteFont>("CS 3505/GameFont");
205 public void UnloadContent()
207 // Nothing to do - the content manager will take care of it.
210 public Vector2 PreferredScreenSize
212 get { return new Vector2(800, 600); }
215 public int MinimumSupportedPlayers
220 public int MaximumSupportedPlayers
225 public void ResetGame(Object[] playerIdentifiers, Object thisPlayer)
227 //if (playerIdentifiers.Length != 4)
228 // throw new Exception("This game requires four players.");
230 // Copy the player identifiers - do not rely on the array parameter not changing.
232 // Now the test harness will at least run with less than 4 players...
233 int numPlayers = playerIdentifiers.Count();
234 for (int i = 0; i < numPlayers; i++)
235 this.playerIdentifiers[i] = playerIdentifiers[i];
237 // Create new game state and inputs objects.
239 state = new GameState();
240 inputs = new NextInputs();
242 // Record 'this' player.
244 this.thisPlayerID = idPlayer(thisPlayer);
247 public long CurrentFrameNumber
249 get { return state.frameNumber; }
252 public long CurrentChecksum
254 get { return state.Checksum; }
257 public void ApplyKeyInput(Object playerIdentifier, Keys key, bool isKeyPressed)
259 int player = idPlayer(playerIdentifier);
261 if (isKeyPressed && !inputs.keysPressed[player].Contains(key))
262 inputs.keysPressed[player].Add(key);
264 if (!isKeyPressed && !inputs.keysReleased[player].Contains(key))
265 inputs.keysReleased[player].Add(key);
268 public void ApplyMouseLocationInput(Object playerIdentifier, int x, int y)
270 int player = idPlayer(playerIdentifier);
271 inputs.mouseLocationX[player] = x;
272 inputs.mouseLocationY[player] = y;
273 inputs.mouseLocationChanged[player] = true;
276 public void ApplyMouseButtonInput(Object playerIdentifier, bool isButtonPressed)
278 int player = idPlayer(playerIdentifier);
279 inputs.mousePressed[player] = isButtonPressed;
280 inputs.mousePressedChanged[player] = true;
283 public bool IsGameOver(Object playerIdentifier)
285 int player = idPlayer(playerIdentifier);
286 return state.isGameOver[player] ;
289 public bool IsTerminated(object playerIdentifier)
291 int player = idPlayer(playerIdentifier);
292 return state.isTerminated[player];
295 public long Update(TimeSpan elapsedTime)
297 state.advanceFrame(inputs, elapsedTime.Milliseconds); // Apply the inputs, advance game state.
299 inputs = new NextInputs(); // Start with inputs cleared on the next frame.
301 return state.frameNumber;
304 public long Draw(SpriteBatch spriteBatch)
306 centerString(spriteBatch, Color.White, "CS 3505 - Software Practice 2", 0, 800, 0);
307 centerString(spriteBatch, Color.White, "Test Harness", 0, 800, 25);
308 centerString(spriteBatch, Color.White, "Debug output", 0, 800, 50);
310 nameIntPair(spriteBatch, Color.White, "Frame:", state.frameNumber, 10, 150, 100);
311 nameHexPair(spriteBatch, Color.White, "Checksum:", state.Checksum, 215, 515, 100);
312 nameDecPair(spriteBatch, Color.White, "Elapsed Time:", state.elapsedTime / 1000.0f, 570, 790, 100);
314 Console.WriteLine("Frame: " + state.frameNumber + " Checksum: " + state.Checksum);
316 printPlayer(spriteBatch, Color.Turquoise, 0, 10, 190, 170);
317 printPlayer(spriteBatch, Color.Wheat, 1, 210, 390, 170);
318 printPlayer(spriteBatch, Color.Tomato, 2, 410, 590, 170);
319 printPlayer(spriteBatch, Color.Violet, 3, 610, 790, 170);
321 if (!state.isGameOver[0])
322 spriteBatch.Draw(crosshair, new Vector2(state.mouseLocationX[0] - 5, state.mouseLocationY[0] - 5), Color.Turquoise);
323 if (!state.isGameOver[1])
324 spriteBatch.Draw(crosshair, new Vector2(state.mouseLocationX[1] - 5, state.mouseLocationY[1] - 5), Color.Wheat);
325 if (!state.isGameOver[2])
326 spriteBatch.Draw(crosshair, new Vector2(state.mouseLocationX[2] - 5, state.mouseLocationY[2] - 5), Color.Tomato);
327 if (!state.isGameOver[3])
328 spriteBatch.Draw(crosshair, new Vector2(state.mouseLocationX[3] - 5, state.mouseLocationY[3] - 5), Color.Violet);
330 spriteBatch.Draw(crosshair, new Vector2(Mouse.GetState().X - 5, Mouse.GetState().Y - 5), Color.White);
332 return state.frameNumber;
337 void printPlayer(SpriteBatch spriteBatch, Color c, int player, float left, float right, float top)
339 leftJustify(spriteBatch, c, String.Format("Player {0}", player+1), left, top);
341 leftJustify(spriteBatch, c, "_________", left, top);
343 nameIntPair(spriteBatch, c, "[X] Game Over", state.isGameOver[player]?1:0, left, right, top);
345 nameIntPair(spriteBatch, c, "[X] Terminated", state.isTerminated[player] ? 1 : 0, left, right, top);
347 nameIntPair(spriteBatch, c, "Mouse X", (int)state.mouseLocationX[player], left, right, top);
349 nameIntPair(spriteBatch, c, "Mouse Y", (int)state.mouseLocationY[player], left, right, top);
351 leftJustify(spriteBatch, c, "Mouse", left, top);
352 rightJustify(spriteBatch, c, state.mouseButton[player]?"Pressed":"Released", right, top);
354 nameIntPair(spriteBatch, c, "Key count", (int)state.keypressCount[player], left, right, top);
356 leftJustify(spriteBatch, c, "Keys", left, top);
357 if (state.keysDown[player].Count == 0)
358 rightJustify(spriteBatch, c, "None", right, top);
360 foreach (Keys k in state.keysDown[player])
362 rightJustify(spriteBatch, c, k.ToString(), right, top);
368 void centerString(SpriteBatch spriteBatch, Color c, String s, float left, float right, float top)
370 Vector2 v = font.MeasureString(s);
371 float x = left + (right-left - v.X) / 2;
373 spriteBatch.DrawString(font, s, new Vector2(x, y), c);
376 void centerString(SpriteBatch spriteBatch, Color c, String s, Rectangle r)
378 Vector2 v = font.MeasureString(s);
379 float x = r.Left + (r.Width - v.X) / 2;
380 float y = r.Top + (r.Height - v.Y) / 2;
381 spriteBatch.DrawString(font, s, new Vector2(x, y), c);
384 void leftJustify(SpriteBatch spriteBatch, Color c, String s, float left, float top)
388 spriteBatch.DrawString(font, s, new Vector2(x, y), c);
391 void rightJustify(SpriteBatch spriteBatch, Color c, String s, float right, float top)
393 Vector2 v = font.MeasureString(s);
394 float x = right - v.X;
396 spriteBatch.DrawString(font, s, new Vector2(x, y), c);
399 void nameDecPair(SpriteBatch spriteBatch, Color c, String name, float number, float left, float right, float top)
401 String num = String.Format("{0:.00}", number);
402 leftJustify(spriteBatch, c, name, left, top);
403 rightJustify(spriteBatch, c, num, right, top);
406 void nameIntPair(SpriteBatch spriteBatch, Color c, String name, long number, float left, float right, float top)
408 String num = String.Format("{0}", number);
409 leftJustify(spriteBatch, c, name, left, top);
410 rightJustify(spriteBatch, c, num, right, top);
413 void nameHexPair(SpriteBatch spriteBatch, Color c, String name, long number, float left, float right, float top)
415 String num = String.Format("{0:x}", number);
416 leftJustify(spriteBatch, c, name, left, top);
417 rightJustify(spriteBatch, c, num, right, top);