From ced3d03bdb3ce866d832e03fb212865140905a9a Mon Sep 17 00:00:00 2001 From: Thomas Leyh Date: Sun, 24 Jul 2016 08:14:18 +0200 Subject: Add project files. --- V3/Map/TiledParser.cs | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 V3/Map/TiledParser.cs (limited to 'V3/Map/TiledParser.cs') diff --git a/V3/Map/TiledParser.cs b/V3/Map/TiledParser.cs new file mode 100644 index 0000000..8171ecf --- /dev/null +++ b/V3/Map/TiledParser.cs @@ -0,0 +1,256 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Xml; +using Microsoft.Xna.Framework; + +namespace V3.Map +{ + /// + /// Parser for the tmx format of the Tiled Map Editor. + /// Reads XML file and returns corresponding data objects. + /// + public sealed class TiledParser + { + private string mFileName; + // Map Data: + public int MapWidth { get; private set; } + public int MapHeight { get; private set; } + public int TileWidth { get; private set; } + public int TileHeight { get; private set; } + public SortedList TileSets { get; } = new SortedList(); + public List MapLayers { get; } = new List(); + public List Areas { get; } = new List(); + + /// + /// Parse the tmx file and hold data in instance properties. + /// + public void Parse(string fileName) + { + mFileName = fileName; + string directory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase); + string fullPath = directory + "/Content/Maps/" + mFileName + ".tmx"; + int p = (int)Environment.OSVersion.Platform; + if ((p == 4) || (p == 6) || (p == 128)) // Running on Unix + fullPath = fullPath.Substring(5); +#if DEBUG + Console.WriteLine("Loading Map: " + fullPath); +#endif + XmlReader reader = XmlReader.Create(fullPath); + while (reader.Read()) + { + if (reader.IsStartElement()) + { + switch (reader.Name) + { + case "map": + ParseMapData(reader); + break; + case "tileset": + ParseTilesetData(reader); + break; + case "layer": + ParseLayerData(reader); + break; + case "objectgroup": + ParseObjectgroup(reader); + break; + } + } + } + } + + private void ParseMapData(XmlReader reader) + { + while (reader.MoveToNextAttribute()) + { + switch (reader.Name) + { + case "width": + MapWidth = reader.ReadContentAsInt(); + break; + case "height": + MapHeight = reader.ReadContentAsInt(); + break; + case "tilewidth": + TileWidth = reader.ReadContentAsInt(); + break; + case "tileheight": + TileHeight = reader.ReadContentAsInt(); + break; + } + } + reader.MoveToElement(); + } + + private void ParseTilesetData(XmlReader reader) + { + if (reader.HasAttributes) + { + List tilesetAttributes = new List(); + // Read attributes firstgid, name, tilewidth, tileheight, tilecount, columns. + for (int i = 0; i < reader.AttributeCount; i++) + { + tilesetAttributes.Add(reader[i]); + } + reader.MoveToElement(); + // Read attributes for tileoffset x and y if existing. + while (reader.Read()) + { + if (reader.Name == "tileoffset") + { + if (reader.IsStartElement()) + { + for (int i = 0; i < reader.AttributeCount; i++) + { + tilesetAttributes.Add(reader[i]); + } + } + else + { + break; + } + } + else if (reader.Name == "tile" || reader.Name == "tileset") + { + break; + } + } + if (tilesetAttributes.Count == 6) + { + TileSets.Add(int.Parse(tilesetAttributes[0]), new Tileset(tilesetAttributes[1], int.Parse(tilesetAttributes[2]), + int.Parse(tilesetAttributes[3]), int.Parse(tilesetAttributes[5]))); + } + else if (tilesetAttributes.Count == 8) + { + TileSets.Add(int.Parse(tilesetAttributes[0]), new Tileset(tilesetAttributes[1], int.Parse(tilesetAttributes[2]), + int.Parse(tilesetAttributes[3]), int.Parse(tilesetAttributes[5]), + int.Parse(tilesetAttributes[6]), int.Parse(tilesetAttributes[7]))); + } + else + { + throw new Exception("Error parsing tileset element in " + mFileName + ".tmx. Does not contain necessary attributes."); + } + ParseCollisionData(reader, int.Parse(tilesetAttributes[0])); + } + } + + private void ParseLayerData(XmlReader reader) + { + while (reader.MoveToNextAttribute()) + { + if (reader.Name == "width") + { + // TODO: Try catching exceptions and throw specific ones. + int width = reader.ReadContentAsInt(); + reader.MoveToNextAttribute(); + int height = reader.ReadContentAsInt(); + reader.MoveToElement(); + reader.ReadToDescendant("data"); + MapLayers.Add(new int[height, width]); + int currentLayerIndex = MapLayers.Count - 1; + // Map data is in CSV format, therefore split at comma. + string[] layerData = reader.ReadString().Split(','); + for (int i = 0; i < height; i++) + { + for (int j = 0; j < width; j++) + { + MapLayers[currentLayerIndex][i, j] = int.Parse(layerData[i * width + j]); + } + } + } + } + reader.MoveToElement(); + } + + private void ParseCollisionData(XmlReader reader, int currentTileset) + { + do + { + if (!reader.IsStartElement() && reader.Name == "tileset") + { + // If the end of the tileset note is reached, leave loop. + break; + } + if (reader.IsStartElement() && reader.Name == "tile" && reader.HasAttributes) + { + string tileId = reader[0]; + reader.MoveToElement(); + while (reader.ReadToDescendant("property")) + { + if (reader.MoveToAttribute("name") && reader.Value == "collision") + { + reader.MoveToNextAttribute(); + string collisionData = reader.Value; + Tileset tileset = TileSets[currentTileset]; + if (tileId != null) tileset.AddCollisionData(int.Parse(tileId), collisionData); + } + } + } + } + while (reader.Read()) ; + } + + private void ParseObjectgroup(XmlReader reader) + { + do + { + if (!reader.IsStartElement() && reader.Name == "objectgroup") + break; + if (reader.IsStartElement() && reader.Name == "object") + { + ParseAreaData(reader); + } + } while (reader.Read()); + } + + private void ParseAreaData(XmlReader reader) + { + string type; + string name = ""; + double density = 0; + double chance = 0; + Rectangle rectangle; + if (reader.AttributeCount == 7) + { + name = reader[1]; + type = reader[2]; + if (!(reader[3] != null && reader[4] != null && reader[5] != null && reader[6] != null)) + return; + rectangle = new Rectangle(int.Parse(reader[3]), int.Parse(reader[4]), int.Parse(reader[5]), int.Parse(reader[6])); + } + else if (reader.AttributeCount == 6) + { + type = reader[1]; + if (!(reader[2] != null && reader[3] != null && reader[4] != null && reader[5] != null)) + return; + rectangle = new Rectangle(int.Parse(reader[2]), int.Parse(reader[3]), int.Parse(reader[4]), int.Parse(reader[5])); + } + else + { + throw new Exception("Error parsing the map. One of the objects has not the right number of attributes, specifically: " + reader.AttributeCount); + } + reader.MoveToElement(); + while (reader.Read()) + { + if (!reader.IsStartElement() && reader.Name == "properties") + break; + if (reader.Name == "property" && reader.HasAttributes) + { + if (reader[2] == null) return; + if (reader[0] == "chance") + { + chance = double.Parse(reader[2], CultureInfo.InvariantCulture); + } + else if (reader[0] == "density") + { + density = double.Parse(reader[2], CultureInfo.InvariantCulture); + } + reader.MoveToElement(); + } + } + Area area = new Area(type, rectangle, density, chance, name); + Areas.Add(area); + } + } +} -- cgit v1.2.1