\r
namespace CarFire\r
{\r
- // Everything in objects built from this class represent the critical game state\r
+ /// <summary>\r
+ /// Container class for the whole state of the game.\r
+ /// </summary>\r
public class GameState\r
{\r
- public long frameNumber;\r
+ #region Public Properties\r
+ private const int hitMonsterScore = 20;\r
+ private const int killMonsterScore = 100;\r
+ public int HitMonsterScore { get { return hitMonsterScore; } }\r
+ public int KillMonsterScore { get { return killMonsterScore; } }\r
\r
- private long checksum;\r
- public long Checksum { get { return checksum; } }\r
+ public long FrameNumber { get { return mFrameNumber; } }\r
\r
- public bool[] isGameOver;\r
- public bool[] isTerminated;\r
+ public long Checksum { get { return mChecksum; } }\r
\r
- // Since this is not a game, I'll just keep track of the user inputs as the game state.\r
+ public int NumberOfPlayers { get { return mNumberOfPlayers; } }\r
+\r
+ public Map Map;\r
+ public List<IEntity> Entities = new List<IEntity>();\r
+ public List<Projectile> mProjectiles = new List<Projectile>();\r
+ public Player[] mCharacters;\r
+ public Display mDisplay;\r
+ public AI AIData;\r
+ #endregion\r
\r
- public int[] mouseLocationX;\r
- public int[] mouseLocationY;\r
- public bool[] mouseButton;\r
- public List<Keys>[] keysDown;\r
- public int[] keypressCount;\r
\r
- public long elapsedTime;\r
+ #region Public Methods\r
\r
- /* Constructor */\r
- public GameState()\r
+ /// <summary>\r
+ /// Construct a game state container with the number of players.\r
+ /// </summary>\r
+ /// <param name="numPlayers">Number of players.</param>\r
+ public GameState(int numPlayers)\r
{\r
- frameNumber = 0;\r
- checksum = 0;\r
+ mNumberOfPlayers = numPlayers;\r
+ mFrameNumber = 0;\r
\r
- isGameOver = new bool[4];\r
- isTerminated = new bool[4];\r
+ mCharacters = new Player[numPlayers];\r
\r
- mouseLocationX = new int[4];\r
- mouseLocationY = new int[4];\r
- mouseButton = new bool[4];\r
- keysDown = new List<Keys>[4];\r
- for (int i = 0; i < 4; i++)\r
- keysDown[i] = new List<Keys>();\r
- keypressCount = new int[4];\r
+ mIsGameOver = new bool[numPlayers];\r
+ mIsTerminated = new bool[numPlayers];\r
\r
- elapsedTime = 0;\r
+ mMouseLocation = new Point[numPlayers];\r
+ mMouseButton = new bool[numPlayers];\r
+ mKeysDown = new List<Keys>[numPlayers];\r
+ for (int i = 0; i < numPlayers; i++) mKeysDown[i] = new List<Keys>();\r
\r
- checksum = 0;\r
+ mKeypressCount = new int[numPlayers];\r
+ mElapsedTime = 0;\r
+ mChecksum = 0;\r
}\r
\r
- /* The game engine! */\r
- public void advanceFrame(NextInputs inputs, long milliseconds)\r
+ \r
+ /// <summary>\r
+ /// Should be called by the Game class to advance the state\r
+ /// to the next frame.\r
+ /// </summary>\r
+ /// <param name="inputs">The inputs that occurred to be\r
+ /// applied this coming frame.</param>\r
+ /// <param name="milliseconds">Milliseconds; used for the checksum.</param>\r
+ public void AdvanceFrame(NextInputs inputs, long milliseconds)\r
{\r
- // Advance frame number\r
- frameNumber++;\r
-\r
- // Advance game - for the test harness, just record statistics and input states.\r
+ mFrameNumber++;\r
+ mElapsedTime += milliseconds;\r
\r
- elapsedTime += milliseconds;\r
-\r
- for (int player = 0; player < 4; player++)\r
+ for (int player = 0; player < NumberOfPlayers; player++)\r
{\r
+ if (inputs.IsMousePressedChanged[player])\r
+ {\r
+ mMouseButton[player] = inputs.MousePressed[player];\r
+ }\r
\r
- //if (isGameOver[player])\r
- // continue;\r
-\r
- if (inputs.mousePressedChanged[player])\r
- mouseButton[player] = inputs.mousePressed[player];\r
-\r
- if (inputs.mouseLocationChanged[player])\r
+ if (inputs.IsMouseLocationChanged[player])\r
{\r
- mouseLocationX[player] = inputs.mouseLocationX[player];\r
- mouseLocationY[player] = inputs.mouseLocationY[player];\r
+ mMouseLocation[player] = inputs.MouseLocation[player];\r
}\r
\r
- foreach (Keys k in inputs.keysPressed[player])\r
- if (!keysDown[player].Contains(k))\r
+ foreach (Keys k in inputs.KeysPressed[player])\r
+ {\r
+ if (!mKeysDown[player].Contains(k))\r
{\r
- keysDown[player].Add(k);\r
- keypressCount[player]++;\r
+ mKeysDown[player].Add(k);\r
+ mKeypressCount[player]++;\r
}\r
+ }\r
\r
- foreach (Keys k in inputs.keysReleased[player])\r
- keysDown[player].Remove(k);\r
-\r
- // If the mouse was pressed for a certain player, activate game over or terminated states as appropriate\r
+ foreach (Keys k in inputs.KeysReleased[player]) mKeysDown[player].Remove(k);\r
+ }\r
\r
- if (inputs.mousePressed[player])\r
- for (int p = 0; p < 4; p++)\r
- {\r
- int x = 200 * p + 10;\r
- int y = 220;\r
-\r
- if (mouseLocationX[player] >= x && mouseLocationY[player] >= y &&\r
- mouseLocationX[player] < x + 25 && mouseLocationY[player] < y + 25)\r
- {\r
- isGameOver[p] = true;\r
- }\r
- y += 25;\r
- if (mouseLocationX[player] >= x && mouseLocationY[player] >= y &&\r
- mouseLocationX[player] < x + 25 && mouseLocationY[player] < y + 25)\r
- {\r
- isGameOver[p] = true;\r
- isTerminated[p] = true;\r
- }\r
- }\r
- \r
+ ComputeChecksum();\r
+ }\r
\r
- }\r
\r
- // Advance the checksum.\r
+ /// <summary>\r
+ /// Get the mouse location for a player.\r
+ /// </summary>\r
+ /// <param name="playerNum">Player Number.</param>\r
+ /// <returns>Mouse location.</returns>\r
+ public Point GetMouseLocation(int playerNum)\r
+ {\r
+ return mMouseLocation[playerNum];\r
+ }\r
\r
- computeChecksum();\r
+ /// <summary>\r
+ /// Get the mouse button state for a player.\r
+ /// </summary>\r
+ /// <param name="playerNum">Player number.</param>\r
+ /// <returns>Mouse button state..</returns>\r
+ public bool GetMouseButton(int playerNum)\r
+ {\r
+ return mMouseButton[playerNum];\r
+ }\r
\r
+ /// <summary>\r
+ /// Get the keyboard state for a player.\r
+ /// </summary>\r
+ /// <param name="playerNum">Player number.</param>\r
+ /// <returns>Keyboard state.</returns>\r
+ public List<Keys> GetKeysDown(int playerNum)\r
+ {\r
+ return mKeysDown[playerNum];\r
}\r
\r
- /* Just hash the values */\r
- private long computeChecksum()\r
+ #endregion\r
+\r
+\r
+ #region Private Methods\r
+\r
+ // Calculates a checksum for debugging network synchronization issues.\r
+ long ComputeChecksum()\r
{\r
- checksum += frameNumber;\r
- for (int i = 0; i < 4; i++)\r
+ mChecksum += FrameNumber;\r
+ for (int i = 0; i < NumberOfPlayers; i++)\r
{\r
- checksum = checksum + keypressCount[i];\r
- checksum = checksum * 3 + (isGameOver[i] ? 1 : 2);\r
- checksum = checksum * 3 + (isTerminated[i] ? 1 : 2);\r
- foreach (Keys k in keysDown[i])\r
- checksum = checksum * 257 + (int)k;\r
- checksum = checksum * 25789 + mouseLocationX[i] * 259 + mouseLocationY[i] + 375;\r
- checksum = checksum * 3 + (mouseButton[i] ? 1 : 2);\r
+ mChecksum = mChecksum + mKeypressCount[i];\r
+ mChecksum = mChecksum * 3 + (mIsGameOver[i] ? 1 : 2);\r
+ mChecksum = mChecksum * 3 + (mIsTerminated[i] ? 1 : 2);\r
+ foreach (Keys k in mKeysDown[i])\r
+ mChecksum = mChecksum * 257 + (int)k;\r
+ mChecksum = mChecksum * 25789 + mMouseLocation[i].X * 259 + mMouseLocation[i].Y + 375;\r
+ mChecksum = mChecksum * 3 + (mMouseButton[i] ? 1 : 2);\r
\r
}\r
- checksum += elapsedTime;\r
+ mChecksum += mElapsedTime;\r
\r
- return checksum;\r
+ return mChecksum;\r
}\r
+\r
+ #endregion\r
+\r
+\r
+ #region Private Variables\r
+\r
+ int mNumberOfPlayers;\r
+ public Point[] mMouseLocation;\r
+ public bool[] mMouseButton;\r
+ public List<Keys>[] mKeysDown;\r
+\r
+ long mFrameNumber;\r
+\r
+ bool[] mIsGameOver;\r
+ bool[] mIsTerminated;\r
+\r
+ int[] mKeypressCount;\r
+ long mElapsedTime;\r
+ long mChecksum;\r
+\r
+ #endregion\r
}\r
- //code from Prof Jensen's TestHarness\r
- // This class encapsulates inputs from the players.\r
+\r
+ /// <summary>\r
+ /// Container class for all the inputs for a single frame.\r
+ /// </summary>\r
public class NextInputs\r
{\r
- public List<Keys>[] keysPressed;\r
- public List<Keys>[] keysReleased;\r
- public int[] mouseLocationX;\r
- public int[] mouseLocationY;\r
- public bool[] mouseLocationChanged;\r
- public bool[] mousePressed;\r
- public bool[] mousePressedChanged;\r
-\r
- public NextInputs()\r
+ public List<Keys>[] KeysPressed;\r
+ public List<Keys>[] KeysReleased;\r
+ public Point[] MouseLocation;\r
+ public bool[] IsMouseLocationChanged;\r
+ public bool[] MousePressed;\r
+ public bool[] IsMousePressedChanged;\r
+\r
+ public NextInputs(int numPlayers)\r
{\r
- keysPressed = new List<Keys>[4];\r
- keysReleased = new List<Keys>[4];\r
- mouseLocationX = new int[4];\r
- mouseLocationY = new int[4];\r
- mouseLocationChanged = new bool[4];\r
- mousePressed = new bool[4];\r
- mousePressedChanged = new bool[4];\r
- for (int i = 0; i < 4; i++)\r
- keysPressed[i] = new List<Keys>();\r
- for (int i = 0; i < 4; i++)\r
- keysReleased[i] = new List<Keys>();\r
+ KeysPressed = new List<Keys>[numPlayers];\r
+ KeysReleased = new List<Keys>[numPlayers];\r
+ IsMouseLocationChanged = new bool[numPlayers];\r
+ MousePressed = new bool[numPlayers];\r
+ IsMousePressedChanged = new bool[numPlayers];\r
+ for (int i = 0; i < numPlayers; i++) KeysPressed[i] = new List<Keys>();\r
+ for (int i = 0; i < numPlayers; i++) KeysReleased[i] = new List<Keys>();\r
}\r
- \r
}\r
\r
+\r
+ /// <summary>\r
+ /// The big kahuna.\r
+ /// </summary>\r
public class Game : IDeterministicGame\r
{\r
- #region IDeterministicGame Members\r
- List<IPlayer> mPlayers;\r
- NextInputs inputs;\r
- Object[] playerIdentifiers;\r
- Display mDisplay;\r
- Map mMap;\r
+ #region Public Properties\r
+\r
+ /// <summary>\r
+ /// Get the content manager associated with this game.\r
+ /// </summary>\r
+ public ContentManager ContentManager { get { return mContentManager; } }\r
+\r
+ /// <summary>\r
+ /// Get the state.\r
+ /// </summary>\r
+ public GameState State;\r
+\r
+ public bool[,] Grid\r
+ {\r
+ get\r
+ {\r
+ bool[,] grid = State.Map.Grid;\r
+ foreach (IEntity entity in State.Entities)\r
+ {\r
+ Point coordinates = entity.Coordinates;\r
+ if (State.Map.IsCellOpen(coordinates)) grid[coordinates.X, coordinates.Y] = false;\r
+ }\r
+ return grid;\r
+ }\r
+ }\r
\r
- GameState state;\r
- int thisPlayerID;\r
+ #endregion\r
+\r
+\r
+ #region Public Methods\r
+\r
+ public IEntity GetEntityAtCoordinates(Point point)\r
+ {\r
+ foreach (IEntity entity in State.Entities)\r
+ {\r
+ if (entity.Coordinates == point) return entity;\r
+ }\r
+ return null;\r
+ }\r
+\r
+ public Player GetPlayerAtCoordinates(Point point)\r
+ {\r
+ foreach (Player player in State.mCharacters)\r
+ {\r
+ if (player != null && player.Coordinates == point) return player;\r
+ }\r
+ return null;\r
+ }\r
+\r
+ public bool IsCellOpen(Point point)\r
+ {\r
+ if (!State.Map.IsCellOpen(point)) return false;\r
+ if (GetEntityAtCoordinates(point) != null) return false;\r
+ return true;\r
+ }\r
\r
public Game()\r
{\r
- mDisplay = new Display();\r
- mPlayers = new List<IPlayer>();\r
- playerIdentifiers = new Object[4];\r
+ \r
+ }\r
+ /// <summary>\r
+ /// This method should be called whenever the players want to move to a new map.\r
+ /// Not implemented yet. Need some way to get next map.\r
+ /// </summary>\r
+ public void startNewMap()\r
+ {\r
+ //TODO somehow get next map\r
+ State.Entities.Clear();\r
+ //State.Map = State.Map.getNextMap();\r
+ for (int i = 0; i < State.mCharacters.Length; i++)\r
+ {\r
+ State.mCharacters[i].Coordinates = State.Map.GetStartingPositionForPlayer(i + 1);\r
+ }\r
+ State.Entities = State.Map.GetAllEntities(this);\r
}\r
public void LoadContent(ContentManager contentManager)\r
{\r
- //Texture2D everything = contentManager.Load<Texture2D>("default");\r
- mDisplay.LoadContent(contentManager);\r
- int currentCenterX = 5; //Creates a map like the one in Display\r
- int currentCenterY = 5;\r
- mMap = contentManager.Load<Map>("Maps/stable");\r
- Map.DefaultTile = contentManager.Load<Texture2D>("default");\r
- mMap.CenterCell = new Vector2(currentCenterX, currentCenterY);\r
+ mContentManager = contentManager;\r
+ menu = mContentManager.Load<SpriteFont>("menuFont");\r
\r
}\r
\r
{\r
}\r
\r
- private int idPlayer(Object playerIdentifier)\r
+ private int GetPlayerNumber(Object playerIdentifier)\r
{\r
- for (int i = 0; i < playerIdentifiers.Length; i++)\r
- if (playerIdentifiers[i] == playerIdentifier)\r
- return i;\r
+ for (int i = 0; i < mPlayerIdentifiers.Length; i++)\r
+ {\r
+ if (mPlayerIdentifiers[i] == playerIdentifier) return i;\r
+ }\r
throw new Exception("Illegal player identifier" + playerIdentifier);\r
}\r
\r
get { return 4; }\r
}\r
\r
- public void ResetGame(object[] PlayerIdentifiers, object thisPlayer)\r
+ public void ResetGame(object[] playerIdentifiers, object thisPlayer)\r
{\r
- // Now the test harness will at least run with less than 4 players...\r
- int numPlayers = PlayerIdentifiers.Count();\r
- for (int i = 0; i < numPlayers; i++)\r
- this.playerIdentifiers[i] = PlayerIdentifiers[i];\r
-\r
- // Create new game state and inputs objects.\r
+ int numPlayers = playerIdentifiers.Count();\r
+\r
+ mPlayerIdentifiers = new object[numPlayers];\r
+ for (int i = 0; i < numPlayers; i++) mPlayerIdentifiers[i] = playerIdentifiers[i];\r
+\r
+ mThisPlayerID = GetPlayerNumber(thisPlayer);\r
+\r
+ State = new GameState(numPlayers);\r
+ mInputs = new NextInputs(numPlayers);\r
+ State.mDisplay = new Display(this);\r
+ State.mDisplay.LoadContent(mContentManager);\r
+\r
+ Texture2D mapTiles = mContentManager.Load<Texture2D>("graphics/wallAndFloorTilesNoEdgeScale");\r
+ Tilemap tilemap = new Tilemap(mapTiles, 10, 7);\r
+ tilemap.SetTile(' ', new Point(4, 5));\r
+ tilemap.SetTile('`', new Point(0, 1));\r
+ tilemap.SetTile('~', new Point(1, 1));\r
+ tilemap.SetTile('!', new Point(3, 1));\r
+ tilemap.SetTile('@', new Point(4, 1));\r
+ tilemap.SetTile('#', new Point(5, 1));\r
+ tilemap.SetTile('$', new Point(6, 1));\r
+ tilemap.SetTile('%', new Point(8, 1));\r
+ tilemap.SetTile('^', new Point(9, 1));\r
+ tilemap.SetTile('&', new Point(0, 2));\r
+ tilemap.SetTile('=', new Point(1, 2));\r
+ tilemap.SetTile('*', new Point(2, 2));\r
+ tilemap.SetTile('(', new Point(4, 2));\r
+ tilemap.SetTile(')', new Point(0, 3));\r
+ tilemap.SetTile('_', new Point(2, 3));\r
+ tilemap.SetTile('-', new Point(9, 3));\r
+ tilemap.SetTile(',', new Point(1, 4));\r
+ tilemap.SetTile('+', new Point(2, 4));\r
+ tilemap.SetTile('[', new Point(3, 4));\r
+ tilemap.SetTile(']', new Point(4, 4));\r
+ tilemap.SetTile('{', new Point(5, 4));\r
+ tilemap.SetTile('}', new Point(6, 4));\r
+ tilemap.SetTile('\\', new Point(8, 4));\r
+ tilemap.SetTile('|', new Point(9, 4));\r
+ tilemap.SetTile(';', new Point(0, 5));\r
+ tilemap.SetTile(':', new Point(1, 5));\r
+ tilemap.SetTile('\'', new Point(2, 5));\r
+ tilemap.SetTile('"', new Point(3, 5));\r
+ tilemap.SetTile('.', new Point(5, 5));\r
+ tilemap.SetTile('<', new Point(6, 5));\r
+ tilemap.SetTile('>', new Point(7, 5));\r
+ tilemap.SetTile('/', new Point(8, 5));\r
+ tilemap.SetTile('?', new Point(9, 5));\r
+\r
+ State.Map = mContentManager.Load<Map>("Maps/level1");\r
+ State.Map.Tilemap = tilemap;\r
+ State.Entities = State.Map.GetAllEntities(this);\r
+\r
+ State.AIData = new AI(this);\r
\r
- state = new GameState();\r
- inputs = new NextInputs();\r
-\r
- // Record 'this' player.\r
-\r
- this.thisPlayerID = idPlayer(thisPlayer);\r
/*\r
mPlayers.Clear();\r
for (int i = 0; i < PlayerIdentifiers.Length; i++)\r
Point starting = mMap.GetStartingPositionForPlayer(i + 1);\r
mPlayers[i].Spawn(new Vector2(starting.X, starting.Y));\r
}\r
- */\r
- \r
+ */\r
}\r
\r
public long CurrentFrameNumber\r
{\r
- get { return state.frameNumber; }\r
+ get { return State.FrameNumber; }\r
}\r
\r
public long CurrentChecksum\r
public void ApplyKeyInput(object playerIdentifier, Keys key, bool isKeyPressed)\r
{\r
//code from Prof Jensen's TestHarness\r
- int player = idPlayer(playerIdentifier);\r
+ int player = GetPlayerNumber(playerIdentifier);\r
\r
- if (isKeyPressed && !inputs.keysPressed[player].Contains(key))\r
- inputs.keysPressed[player].Add(key);\r
+ if (isKeyPressed && !mInputs.KeysPressed[player].Contains(key))\r
+ mInputs.KeysPressed[player].Add(key);\r
\r
- if (!isKeyPressed && !inputs.keysReleased[player].Contains(key))\r
- inputs.keysReleased[player].Add(key);\r
+ if (!isKeyPressed && !mInputs.KeysReleased[player].Contains(key))\r
+ mInputs.KeysReleased[player].Add(key);\r
\r
}\r
\r
\r
public long Update(TimeSpan elapsedTime)\r
{\r
- state.advanceFrame(inputs, elapsedTime.Milliseconds); // Apply the inputs, advance game state.\r
- mDisplay.Update(elapsedTime, state);\r
- inputs = new NextInputs(); // Start with inputs cleared on the next frame.\r
+ State.AdvanceFrame(mInputs, elapsedTime.Milliseconds); // Apply the inputs, advance game state.\r
+ State.mDisplay.Update(elapsedTime, mThisPlayerID);\r
+ State.Entities.ForEach(delegate(IEntity e) { e.Update(elapsedTime); });\r
+ mInputs = new NextInputs(State.NumberOfPlayers); // Start with inputs cleared on the next frame.\r
//mDisplay.Update(elapsedTime);\r
- return state.frameNumber;\r
+ return State.FrameNumber;\r
\r
}\r
\r
public long Draw(SpriteBatch spriteBatch)\r
{\r
- mDisplay.Draw(spriteBatch);\r
+ bool allCharactersSelected = true;\r
+ for (int i = 0; i < State.NumberOfPlayers; i++)\r
+ {\r
+ //If player has not selected a player yet let them select one.\r
+ if (State.mCharacters[i] == null)\r
+ {\r
+ allCharactersSelected = false;\r
+ if (State.GetKeysDown(i).Contains(Keys.M))\r
+ {\r
+ State.mCharacters[i] = new Melee(this, "", State.Map.GetStartingPositionForPlayer(i + 1), i);\r
+ State.mCharacters[i].LoadContent(mContentManager);\r
+ }\r
+ else if (State.GetKeysDown(i).Contains(Keys.R))\r
+ {\r
+ State.mCharacters[i] = new Ranged(this, "", State.Map.GetStartingPositionForPlayer(i + 1), i);\r
+ State.mCharacters[i].LoadContent(mContentManager);\r
+ }\r
+ }\r
+ }\r
+ if (allCharactersSelected)\r
+ {\r
+ \r
+ State.mDisplay.Draw(spriteBatch);\r
+ }\r
+ else\r
+ {\r
+ spriteBatch.GraphicsDevice.Clear(Color.Black);\r
+ spriteBatch.DrawString(menu, "Press R to select a Ranged Character and M to select a Melee Character", new Vector2(30, 30), Color.RosyBrown);\r
+ }\r
return CurrentFrameNumber;\r
}\r
\r
#endregion\r
+\r
+\r
+ #region Private Variables\r
+\r
+ SpriteFont menu;\r
+\r
+ ContentManager mContentManager;\r
+ NextInputs mInputs;\r
+\r
+ Object[] mPlayerIdentifiers;\r
+ int mThisPlayerID;\r
+\r
+ #endregion\r
}\r
}\r