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
18 private const int hitMonsterScore = 20;
19 private const int killMonsterScore = 100;
20 public int HitMonsterScore { get { return hitMonsterScore; } }
21 public int KillMonsterScore { get { return killMonsterScore; } }
23 public long FrameNumber { get { return mFrameNumber; } }
25 public long Checksum { get { return mChecksum; } }
27 public int NumberOfPlayers { get { return mNumberOfPlayers; } }
30 public List<IEntity> Entities = new List<IEntity>();
31 public List<Projectile> mProjectiles = new List<Projectile>();
32 public Player[] mCharacters;
33 public Display mDisplay;
38 #region Public Methods
41 /// Construct a game state container with the number of players.
43 /// <param name="numPlayers">Number of players.</param>
44 public GameState(int numPlayers)
46 mNumberOfPlayers = numPlayers;
49 mCharacters = new Player[numPlayers];
51 mIsGameOver = new bool[numPlayers];
52 mIsTerminated = new bool[numPlayers];
54 mMouseLocation = new Point[numPlayers];
55 mMouseButton = new bool[numPlayers];
56 mKeysDown = new List<Keys>[numPlayers];
57 for (int i = 0; i < numPlayers; i++) mKeysDown[i] = new List<Keys>();
59 mKeypressCount = new int[numPlayers];
66 /// Should be called by the Game class to advance the state
67 /// to the next frame.
69 /// <param name="inputs">The inputs that occurred to be
70 /// applied this coming frame.</param>
71 /// <param name="milliseconds">Milliseconds; used for the checksum.</param>
72 public void AdvanceFrame(NextInputs inputs, long milliseconds)
75 mElapsedTime += milliseconds;
77 for (int player = 0; player < NumberOfPlayers; player++)
79 if (inputs.IsMousePressedChanged[player])
81 mMouseButton[player] = inputs.MousePressed[player];
84 if (inputs.IsMouseLocationChanged[player])
86 mMouseLocation[player] = inputs.MouseLocation[player];
89 foreach (Keys k in inputs.KeysPressed[player])
91 if (!mKeysDown[player].Contains(k))
93 mKeysDown[player].Add(k);
94 mKeypressCount[player]++;
98 foreach (Keys k in inputs.KeysReleased[player]) mKeysDown[player].Remove(k);
106 /// Get the mouse location for a player.
108 /// <param name="playerNum">Player Number.</param>
109 /// <returns>Mouse location.</returns>
110 public Point GetMouseLocation(int playerNum)
112 return mMouseLocation[playerNum];
116 /// Get the mouse button state for a player.
118 /// <param name="playerNum">Player number.</param>
119 /// <returns>Mouse button state..</returns>
120 public bool GetMouseButton(int playerNum)
122 return mMouseButton[playerNum];
126 /// Get the keyboard state for a player.
128 /// <param name="playerNum">Player number.</param>
129 /// <returns>Keyboard state.</returns>
130 public List<Keys> GetKeysDown(int playerNum)
132 return mKeysDown[playerNum];
138 #region Private Methods
140 // Calculates a checksum for debugging network synchronization issues.
141 long ComputeChecksum()
143 mChecksum += FrameNumber;
144 for (int i = 0; i < NumberOfPlayers; i++)
146 mChecksum = mChecksum + mKeypressCount[i];
147 mChecksum = mChecksum * 3 + (mIsGameOver[i] ? 1 : 2);
148 mChecksum = mChecksum * 3 + (mIsTerminated[i] ? 1 : 2);
149 foreach (Keys k in mKeysDown[i])
150 mChecksum = mChecksum * 257 + (int)k;
151 mChecksum = mChecksum * 25789 + mMouseLocation[i].X * 259 + mMouseLocation[i].Y + 375;
152 mChecksum = mChecksum * 3 + (mMouseButton[i] ? 1 : 2);
155 mChecksum += mElapsedTime;
163 #region Private Variables
165 int mNumberOfPlayers;
166 public Point[] mMouseLocation;
167 public bool[] mMouseButton;
168 public List<Keys>[] mKeysDown;
173 bool[] mIsTerminated;
175 int[] mKeypressCount;
183 /// Container class for all the inputs for a single frame.
185 public class NextInputs
187 public List<Keys>[] KeysPressed;
188 public List<Keys>[] KeysReleased;
189 public Point[] MouseLocation;
190 public bool[] IsMouseLocationChanged;
191 public bool[] MousePressed;
192 public bool[] IsMousePressedChanged;
194 public NextInputs(int numPlayers)
196 KeysPressed = new List<Keys>[numPlayers];
197 KeysReleased = new List<Keys>[numPlayers];
198 IsMouseLocationChanged = new bool[numPlayers];
199 MousePressed = new bool[numPlayers];
200 IsMousePressedChanged = new bool[numPlayers];
201 for (int i = 0; i < numPlayers; i++) KeysPressed[i] = new List<Keys>();
202 for (int i = 0; i < numPlayers; i++) KeysReleased[i] = new List<Keys>();
210 public class Game : IDeterministicGame
212 #region Public Properties
215 /// Get the content manager associated with this game.
217 public ContentManager ContentManager { get { return mContentManager; } }
222 public GameState State;
228 bool[,] grid = State.Map.Grid;
229 foreach (IEntity entity in State.Entities)
231 Point coordinates = entity.Coordinates;
232 if (State.Map.IsCellOpen(coordinates)) grid[coordinates.X, coordinates.Y] = false;
241 #region Public Methods
243 public IEntity GetEntityAtCoordinates(Point point)
245 foreach (IEntity entity in State.Entities)
247 if (entity.Coordinates == point) return entity;
252 public Player GetPlayerAtCoordinates(Point point)
254 foreach (Player player in State.mCharacters)
256 if (player != null && player.Coordinates == point) return player;
261 public bool IsCellOpen(Point point)
263 if (!State.Map.IsCellOpen(point)) return false;
264 if (GetEntityAtCoordinates(point) != null) return false;
273 /// This method should be called whenever the players want to move to a new map.
274 /// Not implemented yet. Need some way to get next map.
276 public void startNewMap()
278 //TODO somehow get next map
279 State.Entities.Clear();
280 //State.Map = State.Map.getNextMap();
281 for (int i = 0; i < State.mCharacters.Length; i++)
283 State.mCharacters[i].Coordinates = State.Map.GetStartingPositionForPlayer(i + 1);
285 State.Entities = State.Map.GetAllEntities(this);
287 public void LoadContent(ContentManager contentManager)
289 mContentManager = contentManager;
290 menu = mContentManager.Load<SpriteFont>("menuFont");
294 public void UnloadContent()
298 private int GetPlayerNumber(Object playerIdentifier)
300 for (int i = 0; i < mPlayerIdentifiers.Length; i++)
302 if (mPlayerIdentifiers[i] == playerIdentifier) return i;
304 throw new Exception("Illegal player identifier" + playerIdentifier);
307 public Vector2 PreferredScreenSize
309 get { return new Vector2(800, 600); }
312 public int MinimumSupportedPlayers
317 public int MaximumSupportedPlayers
322 public void ResetGame(object[] playerIdentifiers, object thisPlayer)
324 int numPlayers = playerIdentifiers.Count();
326 mPlayerIdentifiers = new object[numPlayers];
327 for (int i = 0; i < numPlayers; i++) mPlayerIdentifiers[i] = playerIdentifiers[i];
329 mThisPlayerID = GetPlayerNumber(thisPlayer);
331 State = new GameState(numPlayers);
332 mInputs = new NextInputs(numPlayers);
333 State.mDisplay = new Display(this);
334 State.mDisplay.LoadContent(mContentManager);
336 Texture2D mapTiles = mContentManager.Load<Texture2D>("graphics/wallAndFloorTilesNoEdgeScale");
337 Tilemap tilemap = new Tilemap(mapTiles, 10, 7);
338 tilemap.SetTile(' ', new Point(4, 5));
339 tilemap.SetTile('`', new Point(0, 1));
340 tilemap.SetTile('~', new Point(1, 1));
341 tilemap.SetTile('!', new Point(3, 1));
342 tilemap.SetTile('@', new Point(4, 1));
343 tilemap.SetTile('#', new Point(5, 1));
344 tilemap.SetTile('$', new Point(6, 1));
345 tilemap.SetTile('%', new Point(8, 1));
346 tilemap.SetTile('^', new Point(9, 1));
347 tilemap.SetTile('&', new Point(0, 2));
348 tilemap.SetTile('=', new Point(1, 2));
349 tilemap.SetTile('*', new Point(2, 2));
350 tilemap.SetTile('(', new Point(4, 2));
351 tilemap.SetTile(')', new Point(0, 3));
352 tilemap.SetTile('_', new Point(2, 3));
353 tilemap.SetTile('-', new Point(9, 3));
354 tilemap.SetTile(',', new Point(1, 4));
355 tilemap.SetTile('+', new Point(2, 4));
356 tilemap.SetTile('[', new Point(3, 4));
357 tilemap.SetTile(']', new Point(4, 4));
358 tilemap.SetTile('{', new Point(5, 4));
359 tilemap.SetTile('}', new Point(6, 4));
360 tilemap.SetTile('\\', new Point(8, 4));
361 tilemap.SetTile('|', new Point(9, 4));
362 tilemap.SetTile(';', new Point(0, 5));
363 tilemap.SetTile(':', new Point(1, 5));
364 tilemap.SetTile('\'', new Point(2, 5));
365 tilemap.SetTile('"', new Point(3, 5));
366 tilemap.SetTile('.', new Point(5, 5));
367 tilemap.SetTile('<', new Point(6, 5));
368 tilemap.SetTile('>', new Point(7, 5));
369 tilemap.SetTile('/', new Point(8, 5));
370 tilemap.SetTile('?', new Point(9, 5));
372 State.Map = mContentManager.Load<Map>("Maps/level1");
373 State.Map.Tilemap = tilemap;
374 State.Entities = State.Map.GetAllEntities(this);
376 //State.AIData = new AI(this);
380 for (int i = 0; i < PlayerIdentifiers.Length; i++)
382 Human player = new Human(mMap, "");
383 mPlayers.Add(player);
384 mDisplay.AddCharacters(player);
385 mPlayers.Add(player);
386 mDisplay.AddCharacters(player);
388 this.playerIdentifiers = PlayerIdentifiers;
389 for (int i = 0; i < mPlayers.Count; i++)
391 Point starting = mMap.GetStartingPositionForPlayer(i + 1);
392 mPlayers[i].Spawn(new Vector2(starting.X, starting.Y));
397 public long CurrentFrameNumber
399 get { return State.FrameNumber; }
402 public long CurrentChecksum
407 public void ApplyKeyInput(object playerIdentifier, Keys key, bool isKeyPressed)
409 //code from Prof Jensen's TestHarness
410 int player = GetPlayerNumber(playerIdentifier);
412 if (isKeyPressed && !mInputs.KeysPressed[player].Contains(key))
413 mInputs.KeysPressed[player].Add(key);
415 if (!isKeyPressed && !mInputs.KeysReleased[player].Contains(key))
416 mInputs.KeysReleased[player].Add(key);
420 public void ApplyMouseLocationInput(object playerIdentifier, int x, int y)
425 public void ApplyMouseButtonInput(object playerIdentifier, bool isButtonPressed)
430 public bool IsGameOver(object playerIdentifier)
435 public bool IsTerminated(object playerIdentifier)
440 public long Update(TimeSpan elapsedTime)
442 State.AdvanceFrame(mInputs, elapsedTime.Milliseconds); // Apply the inputs, advance game state.
443 State.mDisplay.Update(elapsedTime, mThisPlayerID);
444 State.Entities.ForEach(delegate(IEntity e) { e.Update(elapsedTime); });
445 mInputs = new NextInputs(State.NumberOfPlayers); // Start with inputs cleared on the next frame.
446 //mDisplay.Update(elapsedTime);
447 return State.FrameNumber;
451 public long Draw(SpriteBatch spriteBatch)
453 bool allCharactersSelected = true;
454 for (int i = 0; i < State.NumberOfPlayers; i++)
456 //If player has not selected a player yet let them select one.
457 if (State.mCharacters[i] == null)
459 allCharactersSelected = false;
460 if (State.GetKeysDown(i).Contains(Keys.M))
462 State.mCharacters[i] = new Melee(this, "", State.Map.GetStartingPositionForPlayer(i + 1), i);
463 State.mCharacters[i].LoadContent(mContentManager);
465 else if (State.GetKeysDown(i).Contains(Keys.R))
467 State.mCharacters[i] = new Ranged(this, "", State.Map.GetStartingPositionForPlayer(i + 1), i);
468 State.mCharacters[i].LoadContent(mContentManager);
472 if (allCharactersSelected)
475 State.mDisplay.Draw(spriteBatch);
479 spriteBatch.GraphicsDevice.Clear(Color.Black);
480 spriteBatch.DrawString(menu, "Press R to select a Ranged Character and M to select a Melee Character", new Vector2(30, 30), Color.RosyBrown);
482 return CurrentFrameNumber;
488 #region Private Variables
492 ContentManager mContentManager;
495 Object[] mPlayerIdentifiers;