</Reference>\r
</ItemGroup>\r
<ItemGroup>\r
+ <Compile Include="IEntity.cs" />\r
+ <Compile Include="SaberMonster.cs" />\r
<Compile Include="MovementManager.cs" />\r
<Compile Include="PathFinder.cs" />\r
<Compile Include="ChatInfo.cs" />\r
\r
[A]\r
type = SaberMonster\r
+ speed = 10\r
path = [1,1] [5,6] wait(5) [45,2]\r
- loop = true\r
create = [5,7] [2,3]\r
-[B]\r
- condition = has(key)\r
- event = wait(2) remove([2,6]) remove([2,7])\r
+;[B]\r
+; condition = has(key)\r
+; event = wait(2) remove([2,6]) remove([2,7])\r
\r
; Function ideas:\r
; has(entity) Player has given entity in his inventory.\r
+------------------------------------------------------------------------------+\r
| |\r
| 1 |\r
-| B |\r
+| |\r
| 2 +---- |\r
| | |\r
-| 3 | A |\r
+| 3 | |\r
| | |\r
| 4 | |\r
-| | |\r
+| A | |\r
+-------------+----+ |\r
| | |\r
| | |\r
tileset = FuturisticBuilding\r
numplayers = <1,4>\r
\r
+[M]\r
+ type = SaberMonster\r
+ speed = 10\r
+ path = [16,8] [20,6] wait(5) [56,9] [71,17] [75,2] [11,13]\r
+\r
[maptable]\r
+------------------------------------------------------------------------------+\r
| |\r
| | | |\r
+-------------+----+ | \ / |\r
| | | \ / |\r
-| | | \ / |\r
+| M | | \ / |\r
| | | \ / |\r
| | \ @ # $ % ^ & * ( ) | | |\r
| +-------+ | / \ |\r
IPlayer[] mCharacters = new IPlayer[4];\r
Texture2D everything;\r
Texture2D projectile1;\r
- Map mMap;\r
- int currentCenterX = 5;\r
- int currentCenterY = 5;\r
+ Game mGame;\r
#if SINGLE_TEST\r
List<Keys> mLastPressedKeys = new List<Keys>();\r
#endif\r
- public Display()\r
+ public Display(Game game)\r
{\r
+ mGame = game;\r
/*\r
mMap = aMap;\r
mCharacters = characters;\r
{\r
everything = contentManager.Load<Texture2D>("cs");\r
projectile1 = contentManager.Load<Texture2D>("projectile");\r
- mMap = contentManager.Load<Map>("Maps/stable");\r
- Map.DefaultTile = contentManager.Load<Texture2D>("default");\r
- mMap.CenterCell = new Vector2(currentCenterX,currentCenterY);\r
}\r
\r
/// <summary>\r
for (int i = 0; i < mProjectiles.Count; i++ )\r
{\r
bool removed = false;\r
- if (!mMap.IsCellOpen(new Point(mProjectiles[i].Coordinates.X, mProjectiles[i].Coordinates.Y)))\r
+ if (!mGame.State.Map.IsCellOpen(new Point(mProjectiles[i].Coordinates.X, mProjectiles[i].Coordinates.Y)))\r
{\r
\r
mProjectiles.RemoveAt(i);\r
}\r
}\r
//Update input for each player\r
- for (int i = 0; i < 4; i++)\r
+ for (int i = 0; i < mGame.State.NumberOfPlayers; i++)\r
{\r
//If player has not selected a player yet let them select one.\r
if (mCharacters[i] == null)\r
{\r
- if (state.keysDown[i].Contains(Keys.Enter))\r
+ if (mGame.State.GetKeysDown(i).Contains(Keys.Enter))\r
{\r
- mCharacters[i] = new Human(mMap, "", everything, projectile1, this, mMap.GetStartingPositionForPlayer(i+1));\r
+ mCharacters[i] = new Human(mGame, "", everything, projectile1, this, mGame.State.Map.GetStartingPositionForPlayer(i + 1));\r
}\r
}\r
//Regular player input updates\r
else\r
{\r
\r
- mCharacters[i].MovePlayer(timespan, state.keysDown[i]);\r
+ mCharacters[i].MovePlayer(timespan, mGame.State.GetKeysDown(i));\r
\r
}\r
}\r
if (mCharacters[0] != null)\r
{\r
- mMap.CenterCell = mCharacters[0].Position;\r
+ mGame.State.Map.CenterCell = mCharacters[0].Position;\r
}\r
//Handle wall collisions of projectiles again...\r
for (int i = 0; i < mProjectiles.Count; i++)\r
{\r
- if (!mMap.IsCellOpen(new Point(mProjectiles[i].Coordinates.X, mProjectiles[i].Coordinates.Y)))\r
+ if (!mGame.State.Map.IsCellOpen(new Point(mProjectiles[i].Coordinates.X, mProjectiles[i].Coordinates.Y)))\r
{\r
mProjectiles.RemoveAt(i);\r
i--;\r
}\r
\r
#if INGAME_ZOOM\r
- if (Keyboard.GetState().IsKeyDown(Keys.PageUp)) mMap.Zoom = mMap.Zoom + 0.5f;\r
- if (Keyboard.GetState().IsKeyDown(Keys.PageDown)) mMap.Zoom = mMap.Zoom - 0.5f;\r
+ if (Keyboard.GetState().IsKeyDown(Keys.PageUp)) mGame.State.Map.Zoom = mGame.State.Map.Zoom + 0.5f;\r
+ if (Keyboard.GetState().IsKeyDown(Keys.PageDown)) mGame.State.Map.Zoom = mGame.State.Map.Zoom - 0.5f;\r
#endif\r
}\r
\r
/// <param name="spriteBatch">Used to draw with</param>\r
public void Draw(SpriteBatch spriteBatch)\r
{\r
- mMap.Draw(spriteBatch);\r
+ mGame.State.Map.Draw(spriteBatch);\r
+ mGame.State.Entities.ForEach(delegate(IEntity e) { e.Draw(spriteBatch); });\r
+\r
foreach(Projectile projectile in mProjectiles)\r
{\r
projectile.Draw(spriteBatch);\r
}\r
- for(int i = 0; i < 4; i++)//IPlayer character in mCharacters)\r
+ for(int i = 0; i < mGame.State.NumberOfPlayers; i++)//IPlayer character in mCharacters)\r
{\r
\r
if (mCharacters[i] != null)\r
\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
\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 int[] mouseLocationX;\r
- public int[] mouseLocationY;\r
- public bool[] mouseButton;\r
- public List<Keys>[] keysDown;\r
- public int[] keypressCount;\r
+ public Map Map;\r
+ public List<IEntity> Entities = new List<IEntity>();\r
\r
- public long elapsedTime;\r
+ #endregion\r
\r
- /* Constructor */\r
- public GameState()\r
- {\r
- frameNumber = 0;\r
- checksum = 0;\r
\r
- isGameOver = new bool[4];\r
- isTerminated = new bool[4];\r
+ #region Public Methods\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
+ /// <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
+ mNumberOfPlayers = numPlayers;\r
+ mFrameNumber = 0;\r
\r
- elapsedTime = 0;\r
+ mIsGameOver = new bool[numPlayers];\r
+ mIsTerminated = new bool[numPlayers];\r
\r
- checksum = 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
+ 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
+ grid[coordinates.X, coordinates.Y] = true;\r
+ }\r
+ return grid;\r
+ }\r
+ }\r
+\r
+ #endregion\r
+\r
\r
- GameState state;\r
- int thisPlayerID;\r
+ #region Public Methods\r
+\r
+ public bool IsCellOpen(Point point)\r
+ {\r
+ if (!State.Map.IsCellOpen(point)) return false;\r
+ foreach (IEntity entity in State.Entities)\r
+ {\r
+ if (entity.Coordinates == point) return false;\r
+ }\r
+ return true;\r
+ }\r
\r
public Game()\r
{\r
- mDisplay = new Display();\r
- mPlayers = new List<IPlayer>();\r
- playerIdentifiers = new Object[4];\r
+ mDisplay = new Display(this);\r
}\r
public void LoadContent(ContentManager contentManager)\r
{\r
- //Texture2D everything = contentManager.Load<Texture2D>("default");\r
+ mContentManager = contentManager;\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
- \r
}\r
\r
public void UnloadContent()\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
+ int numPlayers = playerIdentifiers.Count();\r
\r
- // Create new game state and inputs objects.\r
+ mPlayerIdentifiers = new object[numPlayers];\r
+ for (int i = 0; i < numPlayers; i++) mPlayerIdentifiers[i] = playerIdentifiers[i];\r
\r
- state = new GameState();\r
- inputs = new NextInputs();\r
+ mThisPlayerID = GetPlayerNumber(thisPlayer);\r
\r
- // Record 'this' player.\r
+ State = new GameState(numPlayers);\r
+ mInputs = new NextInputs(numPlayers);\r
+\r
+ State.Map = mContentManager.Load<Map>("Maps/stable");\r
+ State.Map.Game = this;\r
+ State.Entities = State.Map.GetAllEntities();\r
+ Map.DefaultTile = mContentManager.Load<Texture2D>("default");\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
+ mDisplay.Update(elapsedTime, State);\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
}\r
\r
#endregion\r
+\r
+\r
+ #region Private Variables\r
+\r
+ Display mDisplay;\r
+\r
+ ContentManager mContentManager;\r
+ NextInputs mInputs;\r
+\r
+ Object[] mPlayerIdentifiers;\r
+ int mThisPlayerID;\r
+\r
+ #endregion\r
}\r
}\r
const int shootCoolDown = 10;\r
State state;\r
String CharName;\r
- Map theMap;\r
+ Game game;\r
Texture2D charModel;\r
Texture2D projectileModel;\r
int health;\r
int projectileCoolDown;\r
\r
\r
- public Human(Map _theMap, String Name, Texture2D model, Texture2D projectile, Display mDisplay, Point position)\r
+ public Human(Game theGame, String Name, Texture2D model, Texture2D projectile, Display mDisplay, Point position)\r
{\r
- theMap = _theMap;\r
+ game = theGame;\r
CharName = Name;\r
theDisplay = mDisplay;\r
health = 100;\r
projectileSpeed = 30;\r
\r
// Speed is the number of grid cells you can move through per second.\r
- mMotion = new MovementManager(position, 5.0f);\r
+ mMotion = new MovementManager(position, 8.0f);\r
}\r
\r
public void LoadContent(ContentManager contentManager)\r
\r
}\r
\r
- public void UnloadContent()\r
- {\r
-\r
- }\r
\r
- public long Update(GameTime gameTime, NetworkManager networkGame)\r
+ public void Update(TimeSpan timeSpan)\r
{\r
- return 0;\r
-\r
}\r
/// <summary>\r
/// This method will draw a character to the screen.\r
/// </summary>\r
/// <param name="spriteBatch"></param>\r
- /// <returns></returns>\r
- public long Draw(SpriteBatch spriteBatch)\r
+ public void Draw(SpriteBatch spriteBatch)\r
{\r
- Rectangle position = theMap.GetRectangleFromCoordinates(mMotion.Position);\r
+ Rectangle position = game.State.Map.GetRectangleFromCoordinates(mMotion.Position);\r
spriteBatch.Draw(charModel, position, Color.White);\r
- return 0;\r
}\r
\r
public int Health { get { return health; } }\r
Point destination = MovementManager.GetNeighborCell(mMotion.Coordinates, moveLeft, moveRight, moveUp, moveDown);\r
if (!keysPressed.Contains(Keys.LeftControl))\r
{\r
- if (theMap.IsCellOpen(destination))\r
+ if (game.IsCellOpen(destination))\r
{\r
mMotion.Update(timeSpan, moveLeft, moveRight, moveUp, moveDown);\r
}\r
toShoot.Normalize();\r
toShoot *= projectileSpeed;\r
projectileCoolDown = shootCoolDown;\r
- theDisplay.AddProjectiles(new Projectile(theMap, projectileModel,\r
+ theDisplay.AddProjectiles(new Projectile(game.State.Map, projectileModel,\r
toShoot, new Point(startX, startY)));\r
\r
/*\r
--- /dev/null
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using Microsoft.Xna.Framework;\r
+using Microsoft.Xna.Framework.Content;\r
+using Microsoft.Xna.Framework.Graphics;\r
+\r
+namespace CarFire\r
+{\r
+ /// <summary>\r
+ /// A class to represent any object that can exist as an\r
+ /// independent piece of the game.\r
+ /// </summary>\r
+ public interface IEntity\r
+ {\r
+ /// <summary>\r
+ /// Load the resources the entity needs.\r
+ /// </summary>\r
+ /// <param name="contentManager">The foobar.</param>\r
+ void LoadContent(ContentManager contentManager);\r
+\r
+ /// <summary>\r
+ /// Update the entity's state.\r
+ /// </summary>\r
+ /// <param name="timeSpan">The timeslice.</param>\r
+ void Update(TimeSpan timeSpan);\r
+\r
+ /// <summary>\r
+ /// Render the entity on the screen.\r
+ /// </summary>\r
+ /// <param name="spriteBatch">The widget.</param>\r
+ void Draw(SpriteBatch spriteBatch);\r
+\r
+ /// <summary>\r
+ /// Get the actual position.\r
+ /// </summary>\r
+ Vector2 Position { get; }\r
+\r
+ /// <summary>\r
+ /// Get the coordinates on the grid.\r
+ /// </summary>\r
+ Point Coordinates { get; }\r
+ }\r
+}\r
\r
namespace CarFire\r
{\r
- public interface ICharacter\r
+ public interface ICharacter : IEntity\r
{\r
- void LoadContent(ContentManager contentManager);\r
- void UnloadContent();\r
- long Update(GameTime gameTime, NetworkManager networkGame);\r
- long Draw(SpriteBatch spriteBatch);\r
int Health { get; }\r
void causeDamageTo(int amount);\r
- Vector2 Position { get; }\r
- Point Coordinates { get; }\r
}\r
\r
public interface IPlayer : ICharacter\r
set { mView.Zoom = value; }\r
}\r
\r
+\r
+ /// <summary>\r
+ /// Get and set the associated game object.\r
+ /// </summary>\r
+ public Game Game\r
+ {\r
+ get { return mData.Game; }\r
+ set { mData.Game = value; }\r
+ }\r
+\r
#endregion\r
\r
\r
/// thrown if there are entities without associated classes.\r
/// </summary>\r
/// <returns>List of entity objects loaded.</returns>\r
- public List<object> GetAllEntities()\r
+ public List<IEntity> GetAllEntities()\r
{\r
return mData.GetAllEntities();\r
}\r
public Point[] PlayerPositions { get { return mPlayerPositions; } }\r
public bool[,] Grid { get { return mBooleanGrid; } }\r
\r
+ public Game Game;\r
+\r
\r
public Model(Metadata metadata, char[,] grid, char defaultTile,\r
List<RawEntity> entities, Point[] playerPositions)\r
}\r
\r
\r
- public List<object> GetAllEntities()\r
+ public List<IEntity> GetAllEntities()\r
{\r
- List<object> list = new List<object>();\r
+ List<IEntity> list = new List<IEntity>();\r
\r
foreach (RawEntity raw in mEntities)\r
{\r
{\r
string typename = raw.Attributes["type"];\r
\r
- object[] args = new object[3];\r
+ object[] args = new object[4];\r
args[0] = raw.Id;\r
args[1] = raw.Position;\r
args[2] = raw.Attributes;\r
+ args[3] = Game;\r
\r
try\r
{\r
-\r
- object entity = Activator.CreateInstance(System.Type.GetType("CarFire." + typename), args);\r
- if (entity != null) list.Add(entity);\r
+ IEntity entity = (IEntity)Activator.CreateInstance(System.Type.GetType("CarFire." + typename), args);\r
+ if (entity != null)\r
+ {\r
+ entity.LoadContent(Game.ContentManager);\r
+ list.Add(entity);\r
+ }\r
else throw new RuntimeException();\r
}\r
#pragma warning disable 0168\r
{\r
if (raw.Attributes.ContainsKey("type") && typename == raw.Attributes["type"])\r
{\r
- object[] args = new object[3];\r
+ object[] args = new object[4];\r
args[0] = raw.Id;\r
args[1] = raw.Position;\r
args[2] = raw.Attributes;\r
+ args[3] = Game;\r
\r
T entity = (T)Activator.CreateInstance(type, args);\r
- if (entity != null) list.Add(entity);\r
+ if (entity != null)\r
+ {\r
+ ((IEntity)entity).LoadContent(Game.ContentManager);\r
+ list.Add(entity);\r
+ }\r
else throw new RuntimeException("Entity of type " + typename + " not loaded because an entity class can't be found.");\r
}\r
}\r
Update(timeSpan, false, false, false, false);\r
}\r
\r
+ /// <summary>\r
+ /// Update the movement manager with the timeslice and a direction.\r
+ /// </summary>\r
+ /// <param name="timeSpan">The timeslice.</param>\r
+ /// <param name="direction">Direction you want to move.</param>\r
+ public void Update(TimeSpan timeSpan, Direction direction)\r
+ {\r
+ if (direction == Direction.Left) Update(timeSpan, true, false, false, false);\r
+ else if (direction == Direction.UpperLeft) Update(timeSpan, true, false, true, false);\r
+ else if (direction == Direction.Up) Update(timeSpan, false, false, true, false);\r
+ else if (direction == Direction.UpperRight) Update(timeSpan, false, true, true, false);\r
+ else if (direction == Direction.Right) Update(timeSpan, false, true, false, false);\r
+ else if (direction == Direction.LowerRight) Update(timeSpan, false, true, false, true);\r
+ else if (direction == Direction.Down) Update(timeSpan, false, false, false, true);\r
+ else if (direction == Direction.LowerLeft) Update(timeSpan, true, false, false, true);\r
+ else Update(timeSpan);\r
+ }\r
+\r
/// <summary>\r
/// Update the movement manager with the timeslice and the directions\r
/// the object is supposed to go. The directions will be ignored if the\r
else return Direction.None;\r
}\r
\r
+ /// <summary>\r
+ /// Helper method to get the general Direction type if you want to move\r
+ /// from one cell to another.\r
+ /// <param name="a">Starting point.</param>\r
+ /// <param name="b">Destination point.</param>\r
+ /// <returns>The direction toward the cell.</returns>\r
+ public static Direction GetDirection(Point a, Point b)\r
+ {\r
+ int dx = b.X - a.X;\r
+ int dy = b.Y - a.Y;\r
+\r
+ if (dx < 0)\r
+ {\r
+ if (dy < 0) return Direction.UpperLeft;\r
+ else if (dy > 0) return Direction.LowerLeft;\r
+ else return Direction.Left;\r
+ }\r
+ else if (dx > 0)\r
+ {\r
+ if (dy < 0) return Direction.UpperRight;\r
+ else if (dy > 0) return Direction.LowerRight;\r
+ else return Direction.Right;\r
+ }\r
+ else if (dy < 0) return Direction.Up;\r
+ else if (dy > 0) return Direction.Down;\r
+ else return Direction.None;\r
+ }\r
+\r
#endregion\r
\r
\r
-using System;\r
+\r
+// Uncomment this to disable diagonal movemet.\r
+//#define ALLOW_DIAGONAL_MOVEMENT\r
+\r
+using System;\r
using System.Collections.Generic;\r
using System.Linq;\r
using System.Text;\r
}\r
\r
List<Point> neighbors = new List<Point>(8);\r
+ neighbors.Add(new Point(cell.Point.X, cell.Point.Y - 1));\r
+ neighbors.Add(new Point(cell.Point.X - 1, cell.Point.Y));\r
+ neighbors.Add(new Point(cell.Point.X + 1, cell.Point.Y));\r
+ neighbors.Add(new Point(cell.Point.X, cell.Point.Y + 1));\r
+#if ALLOW_DIAGONAL_MOVEMENT\r
neighbors.Add(new Point(cell.Point.X - 1, cell.Point.Y - 1));\r
- neighbors.Add(new Point(cell.Point.X + 0, cell.Point.Y - 1));\r
neighbors.Add(new Point(cell.Point.X + 1, cell.Point.Y - 1));\r
- neighbors.Add(new Point(cell.Point.X - 1, cell.Point.Y + 0));\r
- neighbors.Add(new Point(cell.Point.X + 1, cell.Point.Y + 0));\r
neighbors.Add(new Point(cell.Point.X - 1, cell.Point.Y + 1));\r
- neighbors.Add(new Point(cell.Point.X + 0, cell.Point.Y + 1));\r
neighbors.Add(new Point(cell.Point.X + 1, cell.Point.Y + 1));\r
+#endif\r
foreach (Point point in neighbors)\r
{\r
Cell inQueue = mCells[point.X, point.Y];\r
--- /dev/null
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using Microsoft.Xna.Framework;\r
+using Microsoft.Xna.Framework.Content;\r
+using Microsoft.Xna.Framework.Graphics;\r
+\r
+namespace CarFire\r
+{\r
+ public enum AiState\r
+ {\r
+ Standing,\r
+ Pacing,\r
+ Chasing,\r
+ Dazed,\r
+ Fighting,\r
+ Retreating\r
+ }\r
+\r
+\r
+ public class SaberMonster : IMonster\r
+ {\r
+ public SaberMonster(char identifier, Point position, Dictionary<string, string> info, Game game)\r
+ {\r
+ mId = identifier;\r
+ mMotion = new MovementManager(position);\r
+ mGame = game;\r
+\r
+ string speedString;\r
+ if (info.TryGetValue("speed", out speedString))\r
+ {\r
+ int? speed = Parse.Integer(speedString);\r
+ if (speed != null) mMotion.Speed = speed.Value;\r
+ }\r
+\r
+ // Get the "idle path" coordinates loaded from the map.\r
+ string idlePath;\r
+ if (info.TryGetValue("path", out idlePath))\r
+ {\r
+ string[] idlePathPoints = Parse.List(idlePath);\r
+ foreach (string pathPoint in idlePathPoints)\r
+ {\r
+ Point? point = Parse.Coordinates(pathPoint);\r
+ if (point != null) mIdlePath.Add(point.Value);\r
+ }\r
+ }\r
+\r
+ StartPacing();\r
+ }\r
+\r
+\r
+ public void StartPacing()\r
+ {\r
+ mState = AiState.Pacing;\r
+\r
+ if (mIdlePath.Count == 0) return;\r
+\r
+ // Determine the best (closest) waypoint to start at.\r
+ mIdlePathIndex = 0;\r
+ int closest = int.MaxValue;\r
+ for (int i = 0; i < mIdlePath.Count; i++)\r
+ {\r
+ int distance = PathFinder.GetManhattanDistance(Coordinates, mIdlePath[i]);\r
+ if (distance < closest)\r
+ {\r
+ mIdlePathIndex = i;\r
+ closest = distance;\r
+ }\r
+ }\r
+\r
+ PathFinder pathFinder = new PathFinder(mGame.Grid);\r
+ mPath = new List<Point>(32);\r
+ mPath.Add(Coordinates);\r
+ mPath.AddRange(pathFinder.GetPath(mMotion.Coordinates, mIdlePath[mIdlePathIndex]));\r
+ mPath.Add(mIdlePath[mIdlePathIndex]);\r
+ mPathIndex = 0;\r
+ }\r
+\r
+ Direction GetDirectionToNextCell()\r
+ {\r
+ if (mPathIndex >= mPath.Count)\r
+ {\r
+ mIdlePathIndex++;\r
+ PathFinder pathFinder = new PathFinder(mGame.Grid);\r
+ mPath = new List<Point>(32);\r
+ mPath.Add(Coordinates);\r
+ mPath.AddRange(pathFinder.GetPath(mMotion.Coordinates, mIdlePath[mIdlePathIndex % mIdlePath.Count]));\r
+ mPath.Add(mIdlePath[mIdlePathIndex % mIdlePath.Count]);\r
+ mPathIndex = 0;\r
+ }\r
+\r
+ if (mPath[mPathIndex % mPath.Count] == mMotion.Coordinates)\r
+ {\r
+ mPathIndex++;\r
+ mPathDirection = MovementManager.GetDirection(mMotion.Coordinates, mPath[mPathIndex % mPath.Count]);\r
+ }\r
+\r
+ return mPathDirection;\r
+ }\r
+\r
+\r
+ #region IMonster Members\r
+\r
+ public bool visible\r
+ {\r
+ get { throw new NotImplementedException(); }\r
+ }\r
+\r
+ #endregion\r
+\r
+\r
+ #region ICharacter Members\r
+\r
+ public void LoadContent(ContentManager contentManager)\r
+ {\r
+ mTexture = contentManager.Load<Texture2D>("menuItem");\r
+ }\r
+\r
+ public void Update(TimeSpan timeSpan)\r
+ {\r
+ if (mState == AiState.Pacing)\r
+ {\r
+ mMotion.Update(timeSpan, GetDirectionToNextCell());\r
+ }\r
+ }\r
+\r
+ public void Draw(SpriteBatch spriteBatch)\r
+ {\r
+ Rectangle position = mGame.State.Map.GetRectangleFromCoordinates(mMotion.Position);\r
+ spriteBatch.Draw(mTexture, position, Color.White);\r
+ }\r
+\r
+ public int Health\r
+ {\r
+ get { throw new NotImplementedException(); }\r
+ }\r
+\r
+ public void causeDamageTo(int amount)\r
+ {\r
+ throw new NotImplementedException();\r
+ }\r
+\r
+ public Vector2 Position { get { return mMotion.Position; } }\r
+\r
+ public Point Coordinates { get { return mMotion.Coordinates; } }\r
+\r
+ #endregion\r
+\r
+\r
+ #region Private Variables\r
+\r
+ Game mGame;\r
+\r
+ char mId;\r
+ MovementManager mMotion;\r
+\r
+ List<Point> mIdlePath = new List<Point>();\r
+ int mIdlePathIndex;\r
+\r
+ List<Point> mPath;\r
+ int mPathIndex;\r
+ Direction mPathDirection;\r
+\r
+ AiState mState;\r
+\r
+ Texture2D mTexture;\r
+\r
+ #endregion\r
+ }\r
+}\r