X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fcarfire;a=blobdiff_plain;f=CarFire%2FCarFire%2FCarFire%2FGame.cs;h=9a44ff37f16629945ff18469cf4e862935903167;hp=b1b723866dd838003522da855f9121f688c20eb0;hb=f4202b11a1891486216aab3c6b1370fc9a3eb89a;hpb=f5b00f187579c137436bb023c5f4c71dbeb02847 diff --git a/CarFire/CarFire/CarFire/Game.cs b/CarFire/CarFire/CarFire/Game.cs index b1b7238..9a44ff3 100644 --- a/CarFire/CarFire/CarFire/Game.cs +++ b/CarFire/CarFire/CarFire/Game.cs @@ -9,191 +9,334 @@ using Microsoft.Xna.Framework.Input; namespace CarFire { - // Everything in objects built from this class represent the critical game state + /// + /// Container class for the whole state of the game. + /// public class GameState { - public long frameNumber; + #region Public Properties + + public int HitMonsterScore { get { return hitMonsterScore; } } + public int KillMonsterScore { get { return killMonsterScore; } } - private long checksum; - public long Checksum { get { return checksum; } } + public long FrameNumber { get { return mFrameNumber; } } - public bool[] isGameOver; - public bool[] isTerminated; + public long Checksum { get { return mChecksum; } } - // Since this is not a game, I'll just keep track of the user inputs as the game state. + public int NumberOfPlayers { get { return mNumberOfPlayers; } } + + public Map Map; + public List Entities = new List(); + public List mProjectiles = new List(); + public Player[] mCharacters; + public Display mDisplay; + #endregion - public int[] mouseLocationX; - public int[] mouseLocationY; - public bool[] mouseButton; - public List[] keysDown; - public int[] keypressCount; - public long elapsedTime; + #region Public Methods - /* Constructor */ - public GameState() + /// + /// Construct a game state container with the number of players. + /// + /// Number of players. + public GameState(int numPlayers) { - frameNumber = 0; - checksum = 0; + mNumberOfPlayers = numPlayers; + mFrameNumber = 0; - isGameOver = new bool[4]; - isTerminated = new bool[4]; + mCharacters = new Player[numPlayers]; - mouseLocationX = new int[4]; - mouseLocationY = new int[4]; - mouseButton = new bool[4]; - keysDown = new List[4]; - for (int i = 0; i < 4; i++) - keysDown[i] = new List(); - keypressCount = new int[4]; + mIsGameOver = new bool[numPlayers]; + mIsTerminated = new bool[numPlayers]; - elapsedTime = 0; + mMouseLocation = new Point[numPlayers]; + mMouseButton = new bool[numPlayers]; + mKeysDown = new List[numPlayers]; + for (int i = 0; i < numPlayers; i++) mKeysDown[i] = new List(); - checksum = 0; + mKeypressCount = new int[numPlayers]; + mElapsedTime = 0; + mChecksum = 0; } - /* The game engine! */ - public void advanceFrame(NextInputs inputs, long milliseconds) + + /// + /// Should be called by the Game class to advance the state + /// to the next frame. + /// + /// The inputs that occurred to be + /// applied this coming frame. + /// Milliseconds; used for the checksum. + public void AdvanceFrame(NextInputs inputs, long milliseconds) { - // Advance frame number - frameNumber++; - - // Advance game - for the test harness, just record statistics and input states. - - elapsedTime += milliseconds; + mFrameNumber++; + mElapsedTime += milliseconds; - for (int player = 0; player < 4; player++) + for (int player = 0; player < NumberOfPlayers; player++) { + if (inputs.IsMousePressedChanged[player]) + { + mMouseButton[player] = inputs.MousePressed[player]; + } - //if (isGameOver[player]) - // continue; - - if (inputs.mousePressedChanged[player]) - mouseButton[player] = inputs.mousePressed[player]; - - if (inputs.mouseLocationChanged[player]) + if (inputs.IsMouseLocationChanged[player]) { - mouseLocationX[player] = inputs.mouseLocationX[player]; - mouseLocationY[player] = inputs.mouseLocationY[player]; + mMouseLocation[player] = inputs.MouseLocation[player]; } - foreach (Keys k in inputs.keysPressed[player]) - if (!keysDown[player].Contains(k)) + foreach (Keys k in inputs.KeysPressed[player]) + { + if (!mKeysDown[player].Contains(k)) { - keysDown[player].Add(k); - keypressCount[player]++; + mKeysDown[player].Add(k); + mKeypressCount[player]++; } + } - foreach (Keys k in inputs.keysReleased[player]) - keysDown[player].Remove(k); - - // If the mouse was pressed for a certain player, activate game over or terminated states as appropriate + foreach (Keys k in inputs.KeysReleased[player]) mKeysDown[player].Remove(k); + } - if (inputs.mousePressed[player]) - for (int p = 0; p < 4; p++) - { - int x = 200 * p + 10; - int y = 220; - - if (mouseLocationX[player] >= x && mouseLocationY[player] >= y && - mouseLocationX[player] < x + 25 && mouseLocationY[player] < y + 25) - { - isGameOver[p] = true; - } - y += 25; - if (mouseLocationX[player] >= x && mouseLocationY[player] >= y && - mouseLocationX[player] < x + 25 && mouseLocationY[player] < y + 25) - { - isGameOver[p] = true; - isTerminated[p] = true; - } - } - + ComputeChecksum(); + } - } - // Advance the checksum. + /// + /// Get the mouse location for a player. + /// + /// Player Number. + /// Mouse location. + public Point GetMouseLocation(int playerNum) + { + return mMouseLocation[playerNum]; + } - computeChecksum(); + /// + /// Get the mouse button state for a player. + /// + /// Player number. + /// Mouse button state.. + public bool GetMouseButton(int playerNum) + { + return mMouseButton[playerNum]; + } + /// + /// Get the keyboard state for a player. + /// + /// Player number. + /// Keyboard state. + public List GetKeysDown(int playerNum) + { + return mKeysDown[playerNum]; } - /* Just hash the values */ - private long computeChecksum() + #endregion + + + #region Private Methods + + // Calculates a checksum for debugging network synchronization issues. + long ComputeChecksum() { - checksum += frameNumber; - for (int i = 0; i < 4; i++) + mChecksum += FrameNumber; + for (int i = 0; i < NumberOfPlayers; i++) { - checksum = checksum + keypressCount[i]; - checksum = checksum * 3 + (isGameOver[i] ? 1 : 2); - checksum = checksum * 3 + (isTerminated[i] ? 1 : 2); - foreach (Keys k in keysDown[i]) - checksum = checksum * 257 + (int)k; - checksum = checksum * 25789 + mouseLocationX[i] * 259 + mouseLocationY[i] + 375; - checksum = checksum * 3 + (mouseButton[i] ? 1 : 2); + mChecksum = mChecksum + mKeypressCount[i]; + mChecksum = mChecksum * 3 + (mIsGameOver[i] ? 1 : 2); + mChecksum = mChecksum * 3 + (mIsTerminated[i] ? 1 : 2); + foreach (Keys k in mKeysDown[i]) + mChecksum = mChecksum * 257 + (int)k; + mChecksum = mChecksum * 25789 + mMouseLocation[i].X * 259 + mMouseLocation[i].Y + 375; + mChecksum = mChecksum * 3 + (mMouseButton[i] ? 1 : 2); } - checksum += elapsedTime; + mChecksum += mElapsedTime; - return checksum; + return mChecksum; } + + #endregion + + + #region Private Variables + private const int hitMonsterScore = 20; + private const int killMonsterScore = 100; + int mNumberOfPlayers; + public Point[] mMouseLocation; + public bool[] mMouseButton; + public List[] mKeysDown; + + long mFrameNumber; + + bool[] mIsGameOver; + bool[] mIsTerminated; + + int[] mKeypressCount; + long mElapsedTime; + long mChecksum; + + #endregion } - //code from Prof Jensen's TestHarness - // This class encapsulates inputs from the players. + + /// + /// Container class for all the inputs for a single frame. + /// public class NextInputs { - public List[] keysPressed; - public List[] keysReleased; - public int[] mouseLocationX; - public int[] mouseLocationY; - public bool[] mouseLocationChanged; - public bool[] mousePressed; - public bool[] mousePressedChanged; - - public NextInputs() + public List[] KeysPressed; + public List[] KeysReleased; + public Point[] MouseLocation; + public bool[] IsMouseLocationChanged; + public bool[] MousePressed; + public bool[] IsMousePressedChanged; + + public NextInputs(int numPlayers) { - keysPressed = new List[4]; - keysReleased = new List[4]; - mouseLocationX = new int[4]; - mouseLocationY = new int[4]; - mouseLocationChanged = new bool[4]; - mousePressed = new bool[4]; - mousePressedChanged = new bool[4]; - for (int i = 0; i < 4; i++) - keysPressed[i] = new List(); - for (int i = 0; i < 4; i++) - keysReleased[i] = new List(); + KeysPressed = new List[numPlayers]; + KeysReleased = new List[numPlayers]; + IsMouseLocationChanged = new bool[numPlayers]; + MousePressed = new bool[numPlayers]; + IsMousePressedChanged = new bool[numPlayers]; + for (int i = 0; i < numPlayers; i++) KeysPressed[i] = new List(); + for (int i = 0; i < numPlayers; i++) KeysReleased[i] = new List(); } - } + + /// + /// The big kahuna. + /// public class Game : IDeterministicGame { - #region IDeterministicGame Members - List mPlayers; - NextInputs inputs; - Object[] playerIdentifiers; - Display mDisplay; - Map mMap; + #region Public Properties + + /// + /// Get the content manager associated with this game. + /// + public ContentManager ContentManager { get { return mContentManager; } } + + /// + /// Get the state. + /// + public GameState State; + + public bool[,] Grid + { + get + { + bool[,] grid = (bool[,])State.Map.Grid.Clone(); + foreach (IEntity entity in State.Entities) + { + Point coordinates = entity.Coordinates; + grid[coordinates.X, coordinates.Y] = false; + } + foreach (Player player in State.mCharacters) + { + if (player == null) continue; + Point coordinates = player.Coordinates; + grid[coordinates.X, coordinates.Y] = false; + } + return grid; + } + } + + #endregion + + + #region Public Methods + + /// + /// Get an entity at a certain place on the map. + /// + /// The coordinates. + /// The entity, or null if none is at that location. + public IEntity GetEntityAtCoordinates(Point point) + { + foreach (IEntity entity in State.Entities) + { + if (entity.Coordinates == point) return entity; + } + return null; + } + + /// + /// Get a player at a certain place on the map. + /// + /// The coordinates. + /// The player, or null if none is at that location. + public Player GetPlayerAtCoordinates(Point point) + { + foreach (Player player in State.mCharacters) + { + if (player != null && player.Coordinates == point) return player; + } + return null; + } + + /// + /// Determine if a cell is open, depending on the static scenery + /// of the map and if there are any collidable entities. + /// + /// The coordinates. + /// True if the cell is open; false otherwise. + public bool IsCellOpen(Point point) + { + if (!State.Map.IsCellOpen(point)) return false; + IEntity entity = GetEntityAtCoordinates(point); + if (entity != null && entity.IsCollidable) return false; + Player player = GetPlayerAtCoordinates(point); + if (player != null) return false; + return true; + } + + /// + /// Remove a specific entity from the game. The entity can still + /// be tracked some other way, but it won't included when the game is + /// updating and drawing stuff. + /// + /// The entity. + /// The entity that was removed, or null if no entity was removed. + public IEntity RemoveEntity(IEntity entity) + { + if (State.Entities.Remove(entity)) return entity; + return null; + } + + /// + /// Move on to the next map, and advance the level. + /// + public void AdvanceLevel() + { + // TODO: Load the next map, etc... + //TODO somehow get next map + State.Entities.Clear(); + String nextMap = State.Map.Next; + State.Map = mContentManager.Load("Maps/"+nextMap); + for (int i = 0; i < State.mCharacters.Length; i++) + { + State.mCharacters[i].Coordinates = State.Map.GetStartingPositionForPlayer(i + 1); + } + State.Entities = State.Map.GetAllEntities(this); + } + + /// + /// Restart the current level. + /// + public void Reset() + { + State.Map.Reset(); + // TODO: Do other stuff to reset everything. + } - GameState state; - int thisPlayerID; public Game() { - mDisplay = new Display(); - mPlayers = new List(); - playerIdentifiers = new Object[4]; + } public void LoadContent(ContentManager contentManager) { - //Texture2D everything = contentManager.Load("default"); - mDisplay.LoadContent(contentManager); - int currentCenterX = 5; //Creates a map like the one in Display - int currentCenterY = 5; - mMap = contentManager.Load("Maps/stable"); - Map.DefaultTile = contentManager.Load("default"); - mMap.CenterCell = new Vector2(currentCenterX, currentCenterY); + mContentManager = contentManager; + menu = mContentManager.Load("menuFont"); } @@ -201,11 +344,12 @@ namespace CarFire { } - private int idPlayer(Object playerIdentifier) + private int GetPlayerNumber(Object playerIdentifier) { - for (int i = 0; i < playerIdentifiers.Length; i++) - if (playerIdentifiers[i] == playerIdentifier) - return i; + for (int i = 0; i < mPlayerIdentifiers.Length; i++) + { + if (mPlayerIdentifiers[i] == playerIdentifier) return i; + } throw new Exception("Illegal player identifier" + playerIdentifier); } @@ -224,21 +368,64 @@ namespace CarFire get { return 4; } } - public void ResetGame(object[] PlayerIdentifiers, object thisPlayer) + public void ResetGame(object[] playerIdentifiers, object thisPlayer) { - // Now the test harness will at least run with less than 4 players... - int numPlayers = PlayerIdentifiers.Count(); - for (int i = 0; i < numPlayers; i++) - this.playerIdentifiers[i] = PlayerIdentifiers[i]; - - // Create new game state and inputs objects. - - state = new GameState(); - inputs = new NextInputs(); - - // Record 'this' player. + int numPlayers = playerIdentifiers.Count(); + + mPlayerIdentifiers = new object[numPlayers]; + for (int i = 0; i < numPlayers; i++) mPlayerIdentifiers[i] = playerIdentifiers[i]; + + mThisPlayerID = GetPlayerNumber(thisPlayer); + + State = new GameState(numPlayers); + mInputs = new NextInputs(numPlayers); + State.mDisplay = new Display(this); + State.mDisplay.LoadContent(mContentManager); + + // Load the tilemap. + Texture2D mapTiles = mContentManager.Load("graphics/wallAndFloorTilesNoEdgeScale"); + Tilemap tilemap = new Tilemap(mapTiles, 10, 7); + tilemap.SetTile('`', new Point(0, 2), TileFlags.Closed | TileFlags.Wall); + tilemap.SetTile('~', new Point(1, 2), TileFlags.Closed | TileFlags.Wall); + tilemap.SetTile('!', new Point(2, 2), TileFlags.Closed | TileFlags.Wall); + tilemap.SetTile('@', new Point(3, 2), TileFlags.Closed | TileFlags.Wall); + tilemap.SetTile('#', new Point(4, 2), TileFlags.Closed | TileFlags.Wall); + tilemap.SetTile('$', new Point(5, 2), TileFlags.Closed | TileFlags.Wall); + tilemap.SetTile('%', new Point(6, 2), TileFlags.Closed | TileFlags.Wall); + tilemap.SetTile('^', new Point(8, 2), TileFlags.Closed | TileFlags.Wall); + tilemap.SetTile('&', new Point(9, 2), TileFlags.Closed | TileFlags.Wall); + tilemap.SetTile('*', new Point(0, 3), TileFlags.Closed | TileFlags.Wall); + tilemap.SetTile('(', new Point(1, 3), TileFlags.Closed | TileFlags.Wall); + tilemap.SetTile(')', new Point(2, 3), TileFlags.Closed | TileFlags.Wall); + tilemap.SetTile('-', new Point(3, 3), TileFlags.Closed | TileFlags.Wall); + tilemap.SetTile('=', new Point(4, 3), TileFlags.Closed | TileFlags.Wall); + tilemap.SetTile('_', new Point(5, 3), TileFlags.Closed | TileFlags.Wall); + tilemap.SetTile('+', new Point(6, 3), TileFlags.Closed | TileFlags.Wall); + tilemap.SetTile('|', new Point(8, 3), TileFlags.Closed | TileFlags.Wall); + tilemap.SetTile('[', new Point(0, 4), TileFlags.Default); + tilemap.SetTile(']', new Point(1, 4), TileFlags.Default); + tilemap.SetTile('{', new Point(2, 4), TileFlags.Default); + tilemap.SetTile('}', new Point(3, 4), TileFlags.Default); + tilemap.SetTile('?', new Point(4, 4), TileFlags.Default); + tilemap.SetTile(',', new Point(7, 4), TileFlags.Default); + tilemap.SetTile('.', new Point(8, 4), TileFlags.Default); + tilemap.SetTile('\\', new Point(9, 4), TileFlags.Default); + tilemap.SetTile(';', new Point(0, 5), TileFlags.Default); + tilemap.SetTile(':', new Point(1, 5), TileFlags.Default); + tilemap.SetTile('\'', new Point(2, 5), TileFlags.Default); + tilemap.SetTile('"', new Point(3, 5), TileFlags.Default); + tilemap.SetTile(' ', new Point(4, 5), TileFlags.Default); + tilemap.SetTile('<', new Point(7, 5), TileFlags.Default); + tilemap.SetTile('>', new Point(8, 5), TileFlags.Default); + tilemap.SetTile('/', new Point(9, 5), TileFlags.Default); + Map.Tilemap = tilemap; + + // Load the first map. + State.Map = mContentManager.Load("Maps/colosseumClosed"); + State.Entities = State.Map.GetAllEntities(this); + + mAIData = new AI(this); - this.thisPlayerID = idPlayer(thisPlayer); /* mPlayers.Clear(); for (int i = 0; i < PlayerIdentifiers.Length; i++) @@ -255,13 +442,12 @@ namespace CarFire Point starting = mMap.GetStartingPositionForPlayer(i + 1); mPlayers[i].Spawn(new Vector2(starting.X, starting.Y)); } - */ - + */ } public long CurrentFrameNumber { - get { return state.frameNumber; } + get { return State.FrameNumber; } } public long CurrentChecksum @@ -272,13 +458,13 @@ namespace CarFire public void ApplyKeyInput(object playerIdentifier, Keys key, bool isKeyPressed) { //code from Prof Jensen's TestHarness - int player = idPlayer(playerIdentifier); + int player = GetPlayerNumber(playerIdentifier); - if (isKeyPressed && !inputs.keysPressed[player].Contains(key)) - inputs.keysPressed[player].Add(key); + if (isKeyPressed && !mInputs.KeysPressed[player].Contains(key)) + mInputs.KeysPressed[player].Add(key); - if (!isKeyPressed && !inputs.keysReleased[player].Contains(key)) - inputs.keysReleased[player].Add(key); + if (!isKeyPressed && !mInputs.KeysReleased[player].Contains(key)) + mInputs.KeysReleased[player].Add(key); } @@ -304,20 +490,78 @@ namespace CarFire public long Update(TimeSpan elapsedTime) { - state.advanceFrame(inputs, elapsedTime.Milliseconds); // Apply the inputs, advance game state. - mDisplay.Update(elapsedTime, state); - inputs = new NextInputs(); // Start with inputs cleared on the next frame. + State.AdvanceFrame(mInputs, elapsedTime.Milliseconds); // Apply the inputs, advance game state. + State.mDisplay.Update(elapsedTime, mThisPlayerID); + State.Entities.ForEach(delegate(IEntity e) + { + IMonster m = e as IMonster; + if (m != null) + { + if (State.mCharacters[0] != null && mAIData.spaceVisible(e.Coordinates, State.mCharacters[0].Coordinates)) + { + m.Chasing(State.mCharacters[0].Coordinates); + } + else + { + m.DefaultAction(); + } + } + e.Update(elapsedTime); + }); + //State.Entities.ForEach(delegate(IEntity e) { e.Update(elapsedTime); }); + mInputs = new NextInputs(State.NumberOfPlayers); // Start with inputs cleared on the next frame. //mDisplay.Update(elapsedTime); - return state.frameNumber; + return State.FrameNumber; } public long Draw(SpriteBatch spriteBatch) { - mDisplay.Draw(spriteBatch); + bool allCharactersSelected = true; + for (int i = 0; i < State.NumberOfPlayers; i++) + { + //If player has not selected a player yet let them select one. + if (State.mCharacters[i] == null) + { + allCharactersSelected = false; + if (State.GetKeysDown(i).Contains(Keys.M)) + { + State.mCharacters[i] = new Melee(this, "", State.Map.GetStartingPositionForPlayer(i + 1), i); + State.mCharacters[i].LoadContent(mContentManager); + } + else if (State.GetKeysDown(i).Contains(Keys.R)) + { + State.mCharacters[i] = new Ranged(this, "", State.Map.GetStartingPositionForPlayer(i + 1), i); + State.mCharacters[i].LoadContent(mContentManager); + } + } + } + if (allCharactersSelected) + { + + State.mDisplay.Draw(spriteBatch); + } + else + { + spriteBatch.GraphicsDevice.Clear(Color.Black); + spriteBatch.DrawString(menu, "Press R to select a Ranged Character and M to select a Melee Character", new Vector2(30, 30), Color.RosyBrown); + } return CurrentFrameNumber; } #endregion + + + #region Private Variables + + SpriteFont menu; + AI mAIData; + ContentManager mContentManager; + NextInputs mInputs; + + Object[] mPlayerIdentifiers; + int mThisPlayerID; + + #endregion } }