X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fcarfire;a=blobdiff_plain;f=CarFire%2FCarFire%2FCarFire%2FMap.cs;h=8c744bad3e8a96962288d966ea47c991911d099a;hp=c277a7aa4590633359fd50a7d7ef9349f0ec0eff;hb=af9deb873b24dadd0d509ce199fc6cac2b3efbc9;hpb=722dcd763d115992b2a56d4001db80d11e583064 diff --git a/CarFire/CarFire/CarFire/Map.cs b/CarFire/CarFire/CarFire/Map.cs index c277a7a..8c744ba 100644 --- a/CarFire/CarFire/CarFire/Map.cs +++ b/CarFire/CarFire/CarFire/Map.cs @@ -22,9 +22,33 @@ namespace CarFire // DEBUG: Tilesets not implemented at all. public static Texture2D DefaultTile; + #region Public Exceptions + + /// + /// This exception is thrown during the loading of a map if any + /// part of the map file is inconsistent with the expected format + /// and order. + /// + public class RuntimeException : System.ApplicationException + { + public RuntimeException() { } + + public RuntimeException(string message) : + base(message) { } + + public RuntimeException(string message, System.Exception inner) : + base(message, inner) { } + + protected RuntimeException(SerializationInfo info, StreamingContext context) : + base(info, context) { } + } + + #endregion + + #region Public Constants - public const float PixelsToUnitSquares = 8.0f; + public const float PixelsToUnitSquares = 64.0f; #endregion @@ -34,7 +58,7 @@ namespace CarFire /// /// The type of a map helps determine how the map is intended to be used. /// - public enum Type + public enum Mode { None, Campaign, @@ -47,7 +71,7 @@ namespace CarFire public class Metadata { public string Name; - public Type Type; + public Mode Type; public string Author; public HashSet NumPlayers = new HashSet(); public string Tileset; @@ -68,7 +92,7 @@ namespace CarFire #endregion - #region Public Attributes + #region Public Properties /// /// Get the name of the map. @@ -78,7 +102,7 @@ namespace CarFire /// /// Get the type of the map. /// - //public Type Type { get { return mData.mMetadata.Type; } } + public Mode Type { get { return mData.Metadata.Type; } } /// /// Get the author of the map. @@ -104,14 +128,27 @@ namespace CarFire public string Tileset { get { return mData.Metadata.Tileset; } } /// - /// Get a list of the raw entity containers loaded with the map. + /// Get the current grid of open cells. On the grid, true means + /// the cell is open (i.e. an entity can occupy that cell), and false + /// means the cell is closed. Note that, just like Map.IsCellOpen, + /// only static scenery is considered; the grid cannot tell you + /// whether or not an entity is already occupying the cell. + /// + public bool[,] Grid { get { return mData.Grid; } } + + /// + /// Get a list of the raw entity containers loaded with the map. If you + /// want to get the actual entity objects, use Map.GetEntities and + /// Map.GetAllEntities instead. /// public List RawEntities { get { return mData.Entities; } } /// /// Get and set the coordinate of the grid cell that should be in - /// the center of the screen when the map is drawn. + /// the center of the screen when the map is drawn. Setting this + /// will change the viewport of the map and will effect the return + /// values of Map.GetPointFromCoordinates and Map.GetRectangleFromCoordinates. /// public Vector2 CenterCell { @@ -119,6 +156,26 @@ namespace CarFire set { mView.CenterCell = value; } } + /// + /// Get and set the zoom of the map view. The default zoom is + /// Map.PixelsToUnitSquares. + /// + public float Zoom + { + get { return mView.Zoom; } + set { mView.Zoom = value; } + } + + + /// + /// Get and set the associated game object. + /// + public Game Game + { + get { return mData.Game; } + set { mData.Game = value; } + } + #endregion @@ -127,10 +184,13 @@ namespace CarFire /// /// Construct a map with the provided map data. /// - /// Map data. - public Map(Metadata metadata, char[,] grid, List entities) + /// The metadata. + /// The grid. + /// The entities. + public Map(Metadata metadata, char[,] grid, char defaultTile, + List entities, Point[] playerPositions) { - mData = new Modal(metadata, grid, entities); + mData = new Model(metadata, grid, defaultTile, entities, playerPositions); mView = new View(mData); } @@ -210,12 +270,25 @@ namespace CarFire } + /// + /// Get the starting position of a player. + /// + /// The number of the player (i.e. 1-4). + /// This number must be a valid player number. + /// The starting position of the player. + public Point GetStartingPositionForPlayer(int playerNumber) + { + Debug.Assert(1 <= playerNumber && playerNumber <= NumPlayers.Max()); + return mData.PlayerPositions[playerNumber]; + } + + /// /// Get all the entities loaded from the map file. Exceptions could be /// thrown if there are entities without associated classes. /// /// List of entity objects loaded. - public List GetAllEntities() + public List GetAllEntities() { return mData.GetAllEntities(); } @@ -231,18 +304,75 @@ namespace CarFire return mData.GetEntities(); } + + /// + /// Set the tile of a cell. + /// + /// X-coordinate. + /// Y-coordinate. + /// The character representing the tile. + public void SetCell(int x, int y, char tile) + { + mData.SetCell(x, y, tile); + } + + /// + /// Set the tile of a cell. + /// + /// X,Y-coordinates. + /// The character representing the tile. + public void SetCell(Point point, char tile) + { + mData.SetCell(point.X, point.Y, tile); + } + + + /// + /// Clear a cell to the default tile. + /// + /// X-coordinate. + /// Y-coordinate. + public void ClearCell(int x, int y) + { + mData.ClearCell(x, y); + } + + /// + /// Clear a cell to the default tile. + /// + /// X,Y-coordinates. + public void ClearCell(Point point) + { + mData.ClearCell(point.X, point.Y); + } + + + /// + /// Reset the map to the state it was at right after loading. + /// + public void Reset() + { + mData.Reset(); + mView.Reset(); + } + #endregion #region Private Types - class Modal + class Model { - Metadata mMetadata; - char[,] mGrid; - List mEntities; + public Metadata Metadata { get { return mMetadata; } } + public List Entities { get { return mEntities; } } + public Point[] PlayerPositions { get { return mPlayerPositions; } } + public bool[,] Grid { get { return mBooleanGrid; } } + + public Game Game; + - public Modal(Metadata metadata, char[,] grid, List entities) + public Model(Metadata metadata, char[,] grid, char defaultTile, + List entities, Point[] playerPositions) { Debug.Assert(metadata != null); Debug.Assert(grid != null); @@ -250,8 +380,12 @@ namespace CarFire Debug.Assert(metadata.GridWidth * metadata.GridHeight == grid.Length); mMetadata = metadata; - mGrid = grid; + mCleanGrid = grid; + mDefaultTile = defaultTile; mEntities = entities; + mPlayerPositions = playerPositions; + + Reset(); #if DEBUG Console.WriteLine("Loaded map {0} of type {1} written by {2}.", @@ -262,20 +396,51 @@ namespace CarFire } - public Metadata Metadata { get { return mMetadata; } } - public List Entities { get { return mEntities; } } + public void Reset() + { + mGrid = (char[,])mCleanGrid.Clone(); + + mBooleanGrid = new bool[mMetadata.GridWidth, mMetadata.GridHeight]; + for (int x = 0; x < mMetadata.GridWidth; x++) + { + for (int y = 0; y < mMetadata.GridHeight; y++) + { + mBooleanGrid[x, y] = IsCellOpen(x, y); + } + } + } public bool IsCellOpen(int x, int y) { // TODO: Still need to define characters for types of scenery. - return mGrid[x, y] == ' '; + if (IsOnMap(x, y)) return mGrid[x, y] == ' '; + return false; } + public void SetCell(int x, int y, char tile) + { + if (IsOnMap(x, y)) + { + mGrid[x, y] = tile; + mBooleanGrid[x, y] = IsCellOpen(x, y); + } + } - public List GetAllEntities() + public void ClearCell(int x, int y) { - List list = new List(); + SetCell(x, y, mDefaultTile); + } + + public bool IsOnMap(int x, int y) + { + return 0 <= x && x < Metadata.GridWidth && 0 <= y && y < Metadata.GridHeight; + } + + + public List GetAllEntities() + { + List list = new List(); foreach (RawEntity raw in mEntities) { @@ -283,14 +448,28 @@ namespace CarFire { string typename = raw.Attributes["type"]; - object[] args = new object[3]; + object[] args = new object[4]; args[0] = raw.Id; args[1] = raw.Position; args[2] = raw.Attributes; + args[3] = Game; - object entity = Activator.CreateInstance(System.Type.GetType("CarFire." + typename), args); - if (entity != null) list.Add(entity); - else Console.WriteLine("Entity of type " + typename + " not loaded because an entity class can't be found."); + try + { + IEntity entity = (IEntity)Activator.CreateInstance(System.Type.GetType("CarFire." + typename), args); + if (entity != null) + { + entity.LoadContent(Game.ContentManager); + list.Add(entity); + } + else throw new RuntimeException(); + } +#pragma warning disable 0168 + catch (System.Exception ex) +#pragma warning restore 0168 + { + throw new RuntimeException("Entity of type " + typename + " not loaded because an entity class can't be found."); + } } else { @@ -311,35 +490,57 @@ namespace CarFire { if (raw.Attributes.ContainsKey("type") && typename == raw.Attributes["type"]) { - object[] args = new object[3]; + object[] args = new object[4]; args[0] = raw.Id; args[1] = raw.Position; args[2] = raw.Attributes; + args[3] = Game; T entity = (T)Activator.CreateInstance(type, args); - if (entity != null) list.Add(entity); - else Console.WriteLine("Entity of type " + typename + " not loaded because an entity class can't be found."); + if (entity != null) + { + ((IEntity)entity).LoadContent(Game.ContentManager); + list.Add(entity); + } + else throw new RuntimeException("Entity of type " + typename + " not loaded because an entity class can't be found."); } } return list; } + + + Metadata mMetadata; + char[,] mGrid; + char[,] mCleanGrid; + bool[,] mBooleanGrid; + char mDefaultTile; + List mEntities; + Point[] mPlayerPositions; } class View { - Modal mData; - public Vector2 CenterCell; - Viewport mViewport; + public float Zoom; - public View(Modal data) + public View(Model data) { Debug.Assert(data != null); mData = data; + + Reset(); } + + public void Reset() + { + CenterCell = Vector2.Zero; + Zoom = PixelsToUnitSquares; + } + + public void Draw(SpriteBatch spriteBatch) { mViewport = spriteBatch.GraphicsDevice.Viewport; @@ -361,18 +562,30 @@ namespace CarFire } } - /// - /// Get a matrix to transform a point from grid-space to screen coordinates. This - /// method uses the viewport to bound the edges of the map such that the camera - /// will not show anything outside of the grid. - /// - /// The point to put in the center. - /// The transformation matrix. + + public Point GetPointFromCoordinates(float x, float y) + { + Matrix transform = GetTransformation(CenterCell); + Vector2 point = Vector2.Transform(new Vector2(x, y), transform); + + return new Point((int)point.X, (int)point.Y); + } + + public Rectangle GetRectangleFromCoordinates(float x, float y) + { + Matrix transform = GetTransformation(CenterCell); + Vector2 point = Vector2.Transform(new Vector2(x, y), transform); + + return new Rectangle((int)Math.Round(point.X, 0), (int)Math.Round(point.Y, 0), (int)Math.Round(Zoom, 0), (int)Math.Round(Zoom, 0)); + } + + + Matrix GetTransformation(Vector2 center) { - float halfRatio = PixelsToUnitSquares * 0.5f; + float halfRatio = Zoom * 0.5f; Matrix transform = Matrix.CreateTranslation(-center.X, -center.Y, 0.0f); - transform *= Matrix.CreateScale(PixelsToUnitSquares); + transform *= Matrix.CreateScale(Zoom); transform *= Matrix.CreateTranslation(mViewport.Width * 0.5f - halfRatio, mViewport.Height * 0.5f - halfRatio, 0.0f); @@ -393,21 +606,8 @@ namespace CarFire } - public Point GetPointFromCoordinates(float x, float y) - { - Matrix transform = GetTransformation(CenterCell); - Vector2 point = Vector2.Transform(new Vector2(x, y), transform); - - return new Point((int)point.X, (int)point.Y); - } - - public Rectangle GetRectangleFromCoordinates(float x, float y) - { - Matrix transform = GetTransformation(CenterCell); - Vector2 point = Vector2.Transform(new Vector2(x, y), transform); - - return new Rectangle((int)point.X, (int)point.Y, (int)PixelsToUnitSquares, (int)PixelsToUnitSquares); - } + Model mData; + Viewport mViewport; } #endregion @@ -415,7 +615,7 @@ namespace CarFire #region Private Variables - Modal mData; + Model mData; View mView; #endregion