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 IEntity entity = GetEntityAtCoordinates(point);
265 if (entity != null && entity.IsCollidable) return false;
274 /// This method should be called whenever the players want to move to a new map.
275 /// Not implemented yet. Need some way to get next map.
277 public void startNewMap()
279 //TODO somehow get next map
280 State.Entities.Clear();
281 //State.Map = State.Map.getNextMap();
282 for (int i = 0; i < State.mCharacters.Length; i++)
284 State.mCharacters[i].Coordinates = State.Map.GetStartingPositionForPlayer(i + 1);
286 State.Entities = State.Map.GetAllEntities(this);
288 public void LoadContent(ContentManager contentManager)
290 mContentManager = contentManager;
291 menu = mContentManager.Load<SpriteFont>("menuFont");
295 public void UnloadContent()
299 private int GetPlayerNumber(Object playerIdentifier)
301 for (int i = 0; i < mPlayerIdentifiers.Length; i++)
303 if (mPlayerIdentifiers[i] == playerIdentifier) return i;
305 throw new Exception("Illegal player identifier" + playerIdentifier);
308 public Vector2 PreferredScreenSize
310 get { return new Vector2(800, 600); }
313 public int MinimumSupportedPlayers
318 public int MaximumSupportedPlayers
323 public void ResetGame(object[] playerIdentifiers, object thisPlayer)
325 int numPlayers = playerIdentifiers.Count();
327 mPlayerIdentifiers = new object[numPlayers];
328 for (int i = 0; i < numPlayers; i++) mPlayerIdentifiers[i] = playerIdentifiers[i];
330 mThisPlayerID = GetPlayerNumber(thisPlayer);
332 State = new GameState(numPlayers);
333 mInputs = new NextInputs(numPlayers);
334 State.mDisplay = new Display(this);
335 State.mDisplay.LoadContent(mContentManager);
338 Texture2D mapTiles = mContentManager.Load<Texture2D>("graphics/wallAndFloorTilesNoEdgeScale");
339 Tilemap tilemap = new Tilemap(mapTiles, 10, 7);
340 tilemap.SetTile(' ', new Point(4, 5), TileFlags.Default);
341 tilemap.SetTile('`', new Point(0, 1), TileFlags.Closed | TileFlags.Wall);
342 tilemap.SetTile('~', new Point(1, 1), TileFlags.Closed | TileFlags.Wall);
343 tilemap.SetTile('!', new Point(3, 1), TileFlags.Closed | TileFlags.Wall);
344 tilemap.SetTile('@', new Point(4, 1), TileFlags.Closed | TileFlags.Wall);
345 tilemap.SetTile('#', new Point(5, 1), TileFlags.Closed | TileFlags.Wall);
346 tilemap.SetTile('$', new Point(6, 1), TileFlags.Closed | TileFlags.Wall);
347 tilemap.SetTile('%', new Point(8, 1), TileFlags.Closed | TileFlags.Wall);
348 tilemap.SetTile('^', new Point(9, 1), TileFlags.Closed | TileFlags.Wall);
349 tilemap.SetTile('&', new Point(0, 2), TileFlags.Closed | TileFlags.Wall);
350 tilemap.SetTile('=', new Point(1, 2), TileFlags.Closed | TileFlags.Wall);
351 tilemap.SetTile('*', new Point(2, 2), TileFlags.Closed | TileFlags.Wall);
352 tilemap.SetTile('(', new Point(4, 2), TileFlags.Closed | TileFlags.Wall);
353 tilemap.SetTile(')', new Point(0, 3), TileFlags.Closed | TileFlags.Wall);
354 tilemap.SetTile('_', new Point(2, 3), TileFlags.Closed | TileFlags.Wall);
355 tilemap.SetTile('-', new Point(9, 3), TileFlags.Closed | TileFlags.Wall);
356 tilemap.SetTile(',', new Point(1, 4), TileFlags.Default);
357 tilemap.SetTile('+', new Point(2, 4), TileFlags.Default);
358 tilemap.SetTile('[', new Point(3, 4), TileFlags.Default);
359 tilemap.SetTile(']', new Point(4, 4), TileFlags.Default);
360 tilemap.SetTile('{', new Point(5, 4), TileFlags.Default);
361 tilemap.SetTile('}', new Point(6, 4), TileFlags.Default);
362 tilemap.SetTile('\\', new Point(8, 4), TileFlags.Default);
363 tilemap.SetTile('|', new Point(9, 4), TileFlags.Default);
364 tilemap.SetTile(';', new Point(0, 5), TileFlags.Default);
365 tilemap.SetTile(':', new Point(1, 5), TileFlags.Default);
366 tilemap.SetTile('\'', new Point(2, 5), TileFlags.Default);
367 tilemap.SetTile('"', new Point(3, 5), TileFlags.Default);
368 tilemap.SetTile('.', new Point(5, 5), TileFlags.Default);
369 tilemap.SetTile('<', new Point(6, 5), TileFlags.Default);
370 tilemap.SetTile('>', new Point(7, 5), TileFlags.Default);
371 tilemap.SetTile('/', new Point(8, 5), TileFlags.Default);
372 tilemap.SetTile('?', new Point(9, 5), TileFlags.Default);
373 Map.Tilemap = tilemap;
375 // Load the first map.
376 State.Map = mContentManager.Load<Map>("Maps/level1");
377 State.Entities = State.Map.GetAllEntities(this);
379 //State.AIData = new AI(this);
383 for (int i = 0; i < PlayerIdentifiers.Length; i++)
385 Human player = new Human(mMap, "");
386 mPlayers.Add(player);
387 mDisplay.AddCharacters(player);
388 mPlayers.Add(player);
389 mDisplay.AddCharacters(player);
391 this.playerIdentifiers = PlayerIdentifiers;
392 for (int i = 0; i < mPlayers.Count; i++)
394 Point starting = mMap.GetStartingPositionForPlayer(i + 1);
395 mPlayers[i].Spawn(new Vector2(starting.X, starting.Y));
400 public long CurrentFrameNumber
402 get { return State.FrameNumber; }
405 public long CurrentChecksum
410 public void ApplyKeyInput(object playerIdentifier, Keys key, bool isKeyPressed)
412 //code from Prof Jensen's TestHarness
413 int player = GetPlayerNumber(playerIdentifier);
415 if (isKeyPressed && !mInputs.KeysPressed[player].Contains(key))
416 mInputs.KeysPressed[player].Add(key);
418 if (!isKeyPressed && !mInputs.KeysReleased[player].Contains(key))
419 mInputs.KeysReleased[player].Add(key);
423 public void ApplyMouseLocationInput(object playerIdentifier, int x, int y)
428 public void ApplyMouseButtonInput(object playerIdentifier, bool isButtonPressed)
433 public bool IsGameOver(object playerIdentifier)
438 public bool IsTerminated(object playerIdentifier)
443 public long Update(TimeSpan elapsedTime)
445 State.AdvanceFrame(mInputs, elapsedTime.Milliseconds); // Apply the inputs, advance game state.
446 State.mDisplay.Update(elapsedTime, mThisPlayerID);
447 State.Entities.ForEach(delegate(IEntity e) { e.Update(elapsedTime); });
448 mInputs = new NextInputs(State.NumberOfPlayers); // Start with inputs cleared on the next frame.
449 //mDisplay.Update(elapsedTime);
450 return State.FrameNumber;
454 public long Draw(SpriteBatch spriteBatch)
456 bool allCharactersSelected = true;
457 for (int i = 0; i < State.NumberOfPlayers; i++)
459 //If player has not selected a player yet let them select one.
460 if (State.mCharacters[i] == null)
462 allCharactersSelected = false;
463 if (State.GetKeysDown(i).Contains(Keys.M))
465 State.mCharacters[i] = new Melee(this, "", State.Map.GetStartingPositionForPlayer(i + 1), i);
466 State.mCharacters[i].LoadContent(mContentManager);
468 else if (State.GetKeysDown(i).Contains(Keys.R))
470 State.mCharacters[i] = new Ranged(this, "", State.Map.GetStartingPositionForPlayer(i + 1), i);
471 State.mCharacters[i].LoadContent(mContentManager);
475 if (allCharactersSelected)
478 State.mDisplay.Draw(spriteBatch);
482 spriteBatch.GraphicsDevice.Clear(Color.Black);
483 spriteBatch.DrawString(menu, "Press R to select a Ranged Character and M to select a Melee Character", new Vector2(30, 30), Color.RosyBrown);
485 return CurrentFrameNumber;
491 #region Private Variables
495 ContentManager mContentManager;
498 Object[] mPlayerIdentifiers;