2 using System.Collections.Generic;
5 using Microsoft.Xna.Framework;
6 using Microsoft.Xna.Framework.Content;
7 using Microsoft.Xna.Framework.Graphics;
8 using Microsoft.Xna.Framework.Input;
13 /// Container class for the whole state of the game.
15 public class GameState
17 #region Public Properties
19 public long FrameNumber { get { return mFrameNumber; } }
21 public long Checksum { get { return mChecksum; } }
23 public int NumberOfPlayers { get { return mNumberOfPlayers; } }
26 public List<IEntity> Entities = new List<IEntity>();
27 public List<Projectile> mProjectiles = new List<Projectile>();
28 public Player[] mCharacters;
29 public Display mDisplay;
34 #region Public Methods
37 /// Construct a game state container with the number of players.
39 /// <param name="numPlayers">Number of players.</param>
40 public GameState(int numPlayers)
42 mNumberOfPlayers = numPlayers;
45 mCharacters = new Player[numPlayers];
47 mIsGameOver = new bool[numPlayers];
48 mIsTerminated = new bool[numPlayers];
50 mMouseLocation = new Point[numPlayers];
51 mMouseButton = new bool[numPlayers];
52 mKeysDown = new List<Keys>[numPlayers];
53 for (int i = 0; i < numPlayers; i++) mKeysDown[i] = new List<Keys>();
55 mKeypressCount = new int[numPlayers];
62 /// Should be called by the Game class to advance the state
63 /// to the next frame.
65 /// <param name="inputs">The inputs that occurred to be
66 /// applied this coming frame.</param>
67 /// <param name="milliseconds">Milliseconds; used for the checksum.</param>
68 public void AdvanceFrame(NextInputs inputs, long milliseconds)
71 mElapsedTime += milliseconds;
73 for (int player = 0; player < NumberOfPlayers; player++)
75 if (inputs.IsMousePressedChanged[player])
77 mMouseButton[player] = inputs.MousePressed[player];
80 if (inputs.IsMouseLocationChanged[player])
82 mMouseLocation[player] = inputs.MouseLocation[player];
85 foreach (Keys k in inputs.KeysPressed[player])
87 if (!mKeysDown[player].Contains(k))
89 mKeysDown[player].Add(k);
90 mKeypressCount[player]++;
94 foreach (Keys k in inputs.KeysReleased[player]) mKeysDown[player].Remove(k);
102 /// Get the mouse location for a player.
104 /// <param name="playerNum">Player Number.</param>
105 /// <returns>Mouse location.</returns>
106 public Point GetMouseLocation(int playerNum)
108 return mMouseLocation[playerNum];
112 /// Get the mouse button state for a player.
114 /// <param name="playerNum">Player number.</param>
115 /// <returns>Mouse button state..</returns>
116 public bool GetMouseButton(int playerNum)
118 return mMouseButton[playerNum];
122 /// Get the keyboard state for a player.
124 /// <param name="playerNum">Player number.</param>
125 /// <returns>Keyboard state.</returns>
126 public List<Keys> GetKeysDown(int playerNum)
128 return mKeysDown[playerNum];
134 #region Private Methods
136 // Calculates a checksum for debugging network synchronization issues.
137 long ComputeChecksum()
139 mChecksum += FrameNumber;
140 for (int i = 0; i < NumberOfPlayers; i++)
142 mChecksum = mChecksum + mKeypressCount[i];
143 mChecksum = mChecksum * 3 + (mIsGameOver[i] ? 1 : 2);
144 mChecksum = mChecksum * 3 + (mIsTerminated[i] ? 1 : 2);
145 foreach (Keys k in mKeysDown[i])
146 mChecksum = mChecksum * 257 + (int)k;
147 mChecksum = mChecksum * 25789 + mMouseLocation[i].X * 259 + mMouseLocation[i].Y + 375;
148 mChecksum = mChecksum * 3 + (mMouseButton[i] ? 1 : 2);
151 mChecksum += mElapsedTime;
159 #region Private Variables
161 int mNumberOfPlayers;
162 public Point[] mMouseLocation;
163 public bool[] mMouseButton;
164 public List<Keys>[] mKeysDown;
169 bool[] mIsTerminated;
171 int[] mKeypressCount;
179 /// Container class for all the inputs for a single frame.
181 public class NextInputs
183 public List<Keys>[] KeysPressed;
184 public List<Keys>[] KeysReleased;
185 public Point[] MouseLocation;
186 public bool[] IsMouseLocationChanged;
187 public bool[] MousePressed;
188 public bool[] IsMousePressedChanged;
190 public NextInputs(int numPlayers)
192 KeysPressed = new List<Keys>[numPlayers];
193 KeysReleased = new List<Keys>[numPlayers];
194 IsMouseLocationChanged = new bool[numPlayers];
195 MousePressed = new bool[numPlayers];
196 IsMousePressedChanged = new bool[numPlayers];
197 for (int i = 0; i < numPlayers; i++) KeysPressed[i] = new List<Keys>();
198 for (int i = 0; i < numPlayers; i++) KeysReleased[i] = new List<Keys>();
206 public class Game : IDeterministicGame
208 #region Public Properties
211 /// Get the content manager associated with this game.
213 public ContentManager ContentManager { get { return mContentManager; } }
218 public GameState State;
224 bool[,] grid = State.Map.Grid;
225 foreach (IEntity entity in State.Entities)
227 Point coordinates = entity.Coordinates;
228 if (State.Map.IsCellOpen(coordinates)) grid[coordinates.X, coordinates.Y] = false;
237 #region Public Methods
239 public IEntity GetEntityAtCoordinates(Point point)
241 foreach (IEntity entity in State.Entities)
243 if (entity.Coordinates == point) return entity;
248 public Player GetPlayerAtCoordinates(Point point)
250 foreach (Player player in State.mCharacters)
252 if (player != null && player.Coordinates == point) return player;
257 public bool IsCellOpen(Point point)
259 if (!State.Map.IsCellOpen(point)) return false;
260 if (GetEntityAtCoordinates(point) != null) return false;
269 /// This method should be called whenever the players want to move to a new map.
270 /// Not implemented yet. Need some way to get next map.
272 public void startNewMap()
274 //TODO somehow get next map
275 State.Entities.Clear();
276 //State.Map = State.Map.getNextMap();
277 for (int i = 0; i < State.mCharacters.Length; i++)
279 State.mCharacters[i].Coordinates = State.Map.GetStartingPositionForPlayer(i + 1);
281 State.Entities = State.Map.GetAllEntities(this);
283 public void LoadContent(ContentManager contentManager)
285 mContentManager = contentManager;
286 menu = mContentManager.Load<SpriteFont>("menuFont");
290 public void UnloadContent()
294 private int GetPlayerNumber(Object playerIdentifier)
296 for (int i = 0; i < mPlayerIdentifiers.Length; i++)
298 if (mPlayerIdentifiers[i] == playerIdentifier) return i;
300 throw new Exception("Illegal player identifier" + playerIdentifier);
303 public Vector2 PreferredScreenSize
305 get { return new Vector2(800, 600); }
308 public int MinimumSupportedPlayers
313 public int MaximumSupportedPlayers
318 public void ResetGame(object[] playerIdentifiers, object thisPlayer)
320 int numPlayers = playerIdentifiers.Count();
322 mPlayerIdentifiers = new object[numPlayers];
323 for (int i = 0; i < numPlayers; i++) mPlayerIdentifiers[i] = playerIdentifiers[i];
325 mThisPlayerID = GetPlayerNumber(thisPlayer);
327 State = new GameState(numPlayers);
328 mInputs = new NextInputs(numPlayers);
329 State.mDisplay = new Display(this);
330 State.mDisplay.LoadContent(mContentManager);
332 State.Map = mContentManager.Load<Map>("Maps/level1");
333 State.Entities = State.Map.GetAllEntities(this);
334 Map.DefaultTile = mContentManager.Load<Texture2D>("default");
338 for (int i = 0; i < PlayerIdentifiers.Length; i++)
340 Human player = new Human(mMap, "");
341 mPlayers.Add(player);
342 mDisplay.AddCharacters(player);
343 mPlayers.Add(player);
344 mDisplay.AddCharacters(player);
346 this.playerIdentifiers = PlayerIdentifiers;
347 for (int i = 0; i < mPlayers.Count; i++)
349 Point starting = mMap.GetStartingPositionForPlayer(i + 1);
350 mPlayers[i].Spawn(new Vector2(starting.X, starting.Y));
355 public long CurrentFrameNumber
357 get { return State.FrameNumber; }
360 public long CurrentChecksum
365 public void ApplyKeyInput(object playerIdentifier, Keys key, bool isKeyPressed)
367 //code from Prof Jensen's TestHarness
368 int player = GetPlayerNumber(playerIdentifier);
370 if (isKeyPressed && !mInputs.KeysPressed[player].Contains(key))
371 mInputs.KeysPressed[player].Add(key);
373 if (!isKeyPressed && !mInputs.KeysReleased[player].Contains(key))
374 mInputs.KeysReleased[player].Add(key);
378 public void ApplyMouseLocationInput(object playerIdentifier, int x, int y)
383 public void ApplyMouseButtonInput(object playerIdentifier, bool isButtonPressed)
388 public bool IsGameOver(object playerIdentifier)
393 public bool IsTerminated(object playerIdentifier)
398 public long Update(TimeSpan elapsedTime)
400 State.AdvanceFrame(mInputs, elapsedTime.Milliseconds); // Apply the inputs, advance game state.
401 State.mDisplay.Update(elapsedTime, mThisPlayerID);
402 State.Entities.ForEach(delegate(IEntity e) { e.Update(elapsedTime); });
403 mInputs = new NextInputs(State.NumberOfPlayers); // Start with inputs cleared on the next frame.
404 //mDisplay.Update(elapsedTime);
405 return State.FrameNumber;
409 public long Draw(SpriteBatch spriteBatch)
411 bool allCharactersSelected = true;
412 for (int i = 0; i < State.NumberOfPlayers; i++)
414 //If player has not selected a player yet let them select one.
415 if (State.mCharacters[i] == null)
417 allCharactersSelected = false;
418 if (State.GetKeysDown(i).Contains(Keys.M))
420 State.mCharacters[i] = new Melee(this, "", State.Map.GetStartingPositionForPlayer(i + 1), i);
421 State.mCharacters[i].LoadContent(mContentManager);
423 else if (State.GetKeysDown(i).Contains(Keys.R))
425 State.mCharacters[i] = new Ranged(this, "", State.Map.GetStartingPositionForPlayer(i + 1), i);
426 State.mCharacters[i].LoadContent(mContentManager);
430 if (allCharactersSelected)
433 State.mDisplay.Draw(spriteBatch);
437 spriteBatch.GraphicsDevice.Clear(Color.Black);
438 spriteBatch.DrawString(menu, "Press R to select a Ranged Character and M to select a Melee Character", new Vector2(30, 30), Color.RosyBrown);
440 return CurrentFrameNumber;
446 #region Private Variables
450 ContentManager mContentManager;
453 Object[] mPlayerIdentifiers;