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 = (bool[,])State.Map.Grid.Clone();
229 foreach (IEntity entity in State.Entities)
231 Point coordinates = entity.Coordinates;
232 grid[coordinates.X, coordinates.Y] = false;
234 foreach (Player player in State.mCharacters)
236 if (player == null) continue;
237 Point coordinates = player.Coordinates;
238 grid[coordinates.X, coordinates.Y] = false;
247 #region Public Methods
250 /// Get an entity at a certain place on the map.
252 /// <param name="point">The coordinates.</param>
253 /// <returns>The entity, or null if none is at that location.</returns>
254 public IEntity GetEntityAtCoordinates(Point point)
256 foreach (IEntity entity in State.Entities)
258 if (entity.Coordinates == point) return entity;
264 /// Get a player at a certain place on the map.
266 /// <param name="point">The coordinates.</param>
267 /// <returns>The player, or null if none is at that location.</returns>
268 public Player GetPlayerAtCoordinates(Point point)
270 foreach (Player player in State.mCharacters)
272 if (player != null && player.Coordinates == point) return player;
278 /// Determine if a cell is open, depending on the static scenery
279 /// of the map and if there are any collidable entities.
281 /// <param name="point">The coordinates.</param>
282 /// <returns>True if the cell is open; false otherwise.</returns>
283 public bool IsCellOpen(Point point)
285 if (!State.Map.IsCellOpen(point)) return false;
286 IEntity entity = GetEntityAtCoordinates(point);
287 if (entity != null && entity.IsCollidable) return false;
288 Player player = GetPlayerAtCoordinates(point);
289 if (player != null) return false;
294 /// Remove a specific entity from the game. The entity can still
295 /// be tracked some other way, but it won't included when the game is
296 /// updating and drawing stuff.
298 /// <param name="entity">The entity.</param>
299 /// <returns>The entity that was removed, or null if no entity was removed.</returns>
300 public IEntity RemoveEntity(IEntity entity)
302 if (State.Entities.Remove(entity)) return entity;
307 /// Move on to the next map, and advance the level.
309 public void AdvanceLevel()
311 // TODO: Load the next map, etc...
312 //TODO somehow get next map
313 State.Entities.Clear();
314 String nextMap = State.Map.Next;
315 State.Map = mContentManager.Load<Map>("Maps/"+nextMap);
316 for (int i = 0; i < State.mCharacters.Length; i++)
318 State.mCharacters[i].Coordinates = State.Map.GetStartingPositionForPlayer(i + 1);
320 State.Entities = State.Map.GetAllEntities(this);
324 /// Restart the current level.
329 // TODO: Do other stuff to reset everything.
337 public void LoadContent(ContentManager contentManager)
339 mContentManager = contentManager;
340 menu = mContentManager.Load<SpriteFont>("menuFont");
344 public void UnloadContent()
348 private int GetPlayerNumber(Object playerIdentifier)
350 for (int i = 0; i < mPlayerIdentifiers.Length; i++)
352 if (mPlayerIdentifiers[i] == playerIdentifier) return i;
354 throw new Exception("Illegal player identifier" + playerIdentifier);
357 public Vector2 PreferredScreenSize
359 get { return new Vector2(800, 600); }
362 public int MinimumSupportedPlayers
367 public int MaximumSupportedPlayers
372 public void ResetGame(object[] playerIdentifiers, object thisPlayer)
374 int numPlayers = playerIdentifiers.Count();
376 mPlayerIdentifiers = new object[numPlayers];
377 for (int i = 0; i < numPlayers; i++) mPlayerIdentifiers[i] = playerIdentifiers[i];
379 mThisPlayerID = GetPlayerNumber(thisPlayer);
381 State = new GameState(numPlayers);
382 mInputs = new NextInputs(numPlayers);
383 State.mDisplay = new Display(this);
384 State.mDisplay.LoadContent(mContentManager);
387 Texture2D mapTiles = mContentManager.Load<Texture2D>("graphics/wallAndFloorTilesNoEdgeScale");
388 Tilemap tilemap = new Tilemap(mapTiles, 10, 7);
389 tilemap.SetTile('`', new Point(0, 2), TileFlags.Closed | TileFlags.Wall);
390 tilemap.SetTile('~', new Point(1, 2), TileFlags.Closed | TileFlags.Wall);
391 tilemap.SetTile('!', new Point(2, 2), TileFlags.Closed | TileFlags.Wall);
392 tilemap.SetTile('@', new Point(3, 2), TileFlags.Closed | TileFlags.Wall);
393 tilemap.SetTile('#', new Point(4, 2), TileFlags.Closed | TileFlags.Wall);
394 tilemap.SetTile('$', new Point(5, 2), TileFlags.Closed | TileFlags.Wall);
395 tilemap.SetTile('%', new Point(6, 2), TileFlags.Closed | TileFlags.Wall);
396 tilemap.SetTile('^', new Point(8, 2), TileFlags.Closed | TileFlags.Wall);
397 tilemap.SetTile('&', new Point(9, 2), TileFlags.Closed | TileFlags.Wall);
398 tilemap.SetTile('*', new Point(0, 3), TileFlags.Closed | TileFlags.Wall);
399 tilemap.SetTile('(', new Point(1, 3), TileFlags.Closed | TileFlags.Wall);
400 tilemap.SetTile(')', new Point(2, 3), TileFlags.Closed | TileFlags.Wall);
401 tilemap.SetTile('-', new Point(3, 3), TileFlags.Closed | TileFlags.Wall);
402 tilemap.SetTile('=', new Point(4, 3), TileFlags.Closed | TileFlags.Wall);
403 tilemap.SetTile('_', new Point(5, 3), TileFlags.Closed | TileFlags.Wall);
404 tilemap.SetTile('+', new Point(6, 3), TileFlags.Closed | TileFlags.Wall);
405 tilemap.SetTile('|', new Point(8, 3), TileFlags.Closed | TileFlags.Wall);
406 tilemap.SetTile('[', new Point(0, 4), TileFlags.Default);
407 tilemap.SetTile(']', new Point(1, 4), TileFlags.Default);
408 tilemap.SetTile('{', new Point(2, 4), TileFlags.Default);
409 tilemap.SetTile('}', new Point(3, 4), TileFlags.Default);
410 tilemap.SetTile('?', new Point(4, 4), TileFlags.Default);
411 tilemap.SetTile(',', new Point(7, 4), TileFlags.Default);
412 tilemap.SetTile('.', new Point(8, 4), TileFlags.Default);
413 tilemap.SetTile('\\', new Point(9, 4), TileFlags.Default);
414 tilemap.SetTile(';', new Point(0, 5), TileFlags.Default);
415 tilemap.SetTile(':', new Point(1, 5), TileFlags.Default);
416 tilemap.SetTile('\'', new Point(2, 5), TileFlags.Default);
417 tilemap.SetTile('"', new Point(3, 5), TileFlags.Default);
418 tilemap.SetTile(' ', new Point(4, 5), TileFlags.Default);
419 tilemap.SetTile('<', new Point(7, 5), TileFlags.Default);
420 tilemap.SetTile('>', new Point(8, 5), TileFlags.Default);
421 tilemap.SetTile('/', new Point(9, 5), TileFlags.Default);
422 Map.Tilemap = tilemap;
424 // Load the first map.
425 State.Map = mContentManager.Load<Map>("Maps/colosseum");
426 State.Entities = State.Map.GetAllEntities(this);
428 //State.AIData = new AI(this);
432 for (int i = 0; i < PlayerIdentifiers.Length; i++)
434 Human player = new Human(mMap, "");
435 mPlayers.Add(player);
436 mDisplay.AddCharacters(player);
437 mPlayers.Add(player);
438 mDisplay.AddCharacters(player);
440 this.playerIdentifiers = PlayerIdentifiers;
441 for (int i = 0; i < mPlayers.Count; i++)
443 Point starting = mMap.GetStartingPositionForPlayer(i + 1);
444 mPlayers[i].Spawn(new Vector2(starting.X, starting.Y));
449 public long CurrentFrameNumber
451 get { return State.FrameNumber; }
454 public long CurrentChecksum
459 public void ApplyKeyInput(object playerIdentifier, Keys key, bool isKeyPressed)
461 //code from Prof Jensen's TestHarness
462 int player = GetPlayerNumber(playerIdentifier);
464 if (isKeyPressed && !mInputs.KeysPressed[player].Contains(key))
465 mInputs.KeysPressed[player].Add(key);
467 if (!isKeyPressed && !mInputs.KeysReleased[player].Contains(key))
468 mInputs.KeysReleased[player].Add(key);
472 public void ApplyMouseLocationInput(object playerIdentifier, int x, int y)
477 public void ApplyMouseButtonInput(object playerIdentifier, bool isButtonPressed)
482 public bool IsGameOver(object playerIdentifier)
487 public bool IsTerminated(object playerIdentifier)
492 public long Update(TimeSpan elapsedTime)
494 State.AdvanceFrame(mInputs, elapsedTime.Milliseconds); // Apply the inputs, advance game state.
495 State.mDisplay.Update(elapsedTime, mThisPlayerID);
496 State.Entities.ForEach(delegate(IEntity e) { e.Update(elapsedTime); });
497 mInputs = new NextInputs(State.NumberOfPlayers); // Start with inputs cleared on the next frame.
498 //mDisplay.Update(elapsedTime);
499 return State.FrameNumber;
503 public long Draw(SpriteBatch spriteBatch)
505 bool allCharactersSelected = true;
506 for (int i = 0; i < State.NumberOfPlayers; i++)
508 //If player has not selected a player yet let them select one.
509 if (State.mCharacters[i] == null)
511 allCharactersSelected = false;
512 if (State.GetKeysDown(i).Contains(Keys.M))
514 State.mCharacters[i] = new Melee(this, "", State.Map.GetStartingPositionForPlayer(i + 1), i);
515 State.mCharacters[i].LoadContent(mContentManager);
517 else if (State.GetKeysDown(i).Contains(Keys.R))
519 State.mCharacters[i] = new Ranged(this, "", State.Map.GetStartingPositionForPlayer(i + 1), i);
520 State.mCharacters[i].LoadContent(mContentManager);
524 if (allCharactersSelected)
527 State.mDisplay.Draw(spriteBatch);
531 spriteBatch.GraphicsDevice.Clear(Color.Black);
532 spriteBatch.DrawString(menu, "Press R to select a Ranged Character and M to select a Melee Character", new Vector2(30, 30), Color.RosyBrown);
534 return CurrentFrameNumber;
540 #region Private Variables
544 ContentManager mContentManager;
547 Object[] mPlayerIdentifiers;