From ea19cff8fabf1036ed32773708bebb8bb10148e6 Mon Sep 17 00:00:00 2001 From: nolemretaW Date: Wed, 13 Sep 2023 00:45:43 +0200 Subject: [PATCH] corrected layering, added embedded tileset support, and added a example --- README.md | 4 +- TiledCSPlus.Example/Program.cs | 37 +++++++++ .../TiledCSPlus.Example.csproj | 26 ++++++ TiledCSPlus.Example/assets/tilemap.tmx | 9 +++ TiledCSPlus.Example/assets/tileset.png | Bin 0 -> 149 bytes TiledCSPlus.Example/assets/tileset.tsx | 4 + TiledCSPlus.Test/TiledMap.cs | 11 ++- .../assets/TiledCSPlus_test.tiled-session | 31 ++++++-- TiledCSPlus.Test/assets/tilemap.tmx | 10 ++- TiledCSPlus/TiledMap.cs | 75 +++++++++++------- TiledCSPlus/TiledModels.cs | 49 ++---------- TiledCSPlus/TiledTileset.cs | 6 +- 12 files changed, 179 insertions(+), 83 deletions(-) create mode 100644 TiledCSPlus.Example/Program.cs create mode 100644 TiledCSPlus.Example/TiledCSPlus.Example.csproj create mode 100644 TiledCSPlus.Example/assets/tilemap.tmx create mode 100644 TiledCSPlus.Example/assets/tileset.png create mode 100644 TiledCSPlus.Example/assets/tileset.tsx diff --git a/README.md b/README.md index 765f8de..a934fa7 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ TiledCSPlus is an extended, and up to date fork of [TiledCS](https://github.com/ ## Planned features * Support for Tiled 1.9 and 1.10 features. -* Embedded tilesets -* Better layer arrangement (layers will be arranged in order from top to bottom, instead of current tile layers, then object layers, and image layers at the end) +* ~~Embedded tilesets~~ Done! +* ~~Better layer arrangement (layers will be arranged in order from top to bottom, instead of current tile layers, then object layers, and image layers at the end)~~ Also done! ## Does it break compability? **YES**, practically every field was renamed to be in PascalCase, and few fields were combined into one property eg. `offsetX` and `offsetY` into `Vector2` `offset`. Except those few changes, API didn't change much as of now. diff --git a/TiledCSPlus.Example/Program.cs b/TiledCSPlus.Example/Program.cs new file mode 100644 index 0000000..e466793 --- /dev/null +++ b/TiledCSPlus.Example/Program.cs @@ -0,0 +1,37 @@ +using TiledCSPlus; + +class Program +{ + public static void Main(string[] args) + { + //load a tilemap + TiledMap TiledMap = new TiledMap("assets/tilemap.tmx"); + + //load a tileset by loading all used tilesets from a directory + Dictionary Tilesets = TiledMap.GetTiledTilesets("assets/"); + //you can load them manually of course, like this + /* foreach (TiledMapTileset tiledMapTileset in TiledMap.Tilesets) + { + if tileset is not embedded into tilemap + if (!tiledMapTileset.IsTilesetEmbedded) + { + load a tileset file using tiledMapTileset.Source as a filename... + ...using new TiledTileset() + TiledTileset tiledTileset = new TiledTileset(tiledMapTileset.Source); + ..or other method that works for you, into a MemoryStream + MemoryStream ms = new MemoryStream(); //file has to be loaded into a byte array + TiledTileset tiledTileset = new TiledTileset(ms); + + //then, add into loaded tilesets as usual + Tilesets.Add(tiledMapTileset.FirstGid, tiledTileset); + } + } */ + + //get map tileset which some tile belongs to + TiledMapTileset tileMapTileset = TiledMap.GetTiledMapTileset(TiledMap.Layers[0].Data[0]); + //now that you have tileset laded into Tilesets dictionary, you can get the tileset by + TiledTileset tileTileset = Tilesets[tileMapTileset.FirstGid]; + //and now, get the rect for tile's position in the tileset image + TiledSourceRect rect = TiledMap.GetSourceRect(tileMapTileset, tileTileset, TiledMap.Layers[0].Data[0]); + } +} \ No newline at end of file diff --git a/TiledCSPlus.Example/TiledCSPlus.Example.csproj b/TiledCSPlus.Example/TiledCSPlus.Example.csproj new file mode 100644 index 0000000..3a4fb3a --- /dev/null +++ b/TiledCSPlus.Example/TiledCSPlus.Example.csproj @@ -0,0 +1,26 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + + + Always + + + Always + + + Always + + + + diff --git a/TiledCSPlus.Example/assets/tilemap.tmx b/TiledCSPlus.Example/assets/tilemap.tmx new file mode 100644 index 0000000..a13b966 --- /dev/null +++ b/TiledCSPlus.Example/assets/tilemap.tmx @@ -0,0 +1,9 @@ + + + + + + AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAA== + + + diff --git a/TiledCSPlus.Example/assets/tileset.png b/TiledCSPlus.Example/assets/tileset.png new file mode 100644 index 0000000000000000000000000000000000000000..67b9eeea3c0801c3a7092d76b229e2560ee5d7c0 GIT binary patch literal 149 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucK`l=g#}Etu})QSZQ qC$3zWaLH~Bhp(&*Z!NEp7Q<%lsS3|M&zb^tF?hQAxvX + + + diff --git a/TiledCSPlus.Test/TiledMap.cs b/TiledCSPlus.Test/TiledMap.cs index b9eb340..6d09f87 100644 --- a/TiledCSPlus.Test/TiledMap.cs +++ b/TiledCSPlus.Test/TiledMap.cs @@ -26,13 +26,22 @@ public void MapMetadata() [Test] public void Tileset() { - Tilesets[1].Name.ShouldBe("tileset"); + TiledMap.Tilesets[0].FirstGid.ShouldBe(1); + TiledMap.Tilesets[0].Source.ShouldBe("tileset.tsx"); + TiledMap.Tilesets[0].IsTilesetEmbedded.ShouldBe(false); + TiledMap.Tilesets[1].FirstGid.ShouldBe(2); + TiledMap.Tilesets[1].Source.ShouldBe(null); + TiledMap.Tilesets[1].IsTilesetEmbedded.ShouldBe(true); + Tilesets[1].Image.Source.ShouldBe("tileset.png"); + TiledMap.EmbeddedTilesets[2].Name.ShouldBe("tileset-embedded"); + } [Test] public void Layers() { TiledMap.Layers[0].TintColor.ShouldBe(new Color(255, 254, 253, 252)); + TiledMap.Layers[2].Name.ShouldBe("Image Layer 1"); } } \ No newline at end of file diff --git a/TiledCSPlus.Test/assets/TiledCSPlus_test.tiled-session b/TiledCSPlus.Test/assets/TiledCSPlus_test.tiled-session index eee4c34..fd674f3 100644 --- a/TiledCSPlus.Test/assets/TiledCSPlus_test.tiled-session +++ b/TiledCSPlus.Test/assets/TiledCSPlus_test.tiled-session @@ -3,7 +3,7 @@ "height": 4300, "width": 2 }, - "activeFile": "tilemap.tmx", + "activeFile": "D:/Projects/csharp/TiledCSPlus/TiledCSPlus.Example/assets/tilemap.tmx", "expandedProjectPaths": [ "." ], @@ -12,17 +12,34 @@ "": { "scaleInDock": 1 }, + "D:/Projects/csharp/TiledCSPlus/TiledCSPlus.Example/assets/tilemap.tmx": { + "scale": 7.43375, + "selectedLayer": 0, + "viewCenter": { + "x": 84.54683033462251, + "y": 79.50227005212713 + } + }, + "D:/Projects/csharp/TiledCSPlus/TiledCSPlus.Example/assets/tilemap.tmx#tileset-embedded": { + "scaleInDock": 1 + }, + "D:/Projects/csharp/TiledCSPlus/TiledCSPlus.Example/assets/tileset.tsx": { + "scaleInDock": 1 + }, "tilemap.tmx": { "scale": 4, "selectedLayer": 0, "viewCenter": { - "x": -35.375, - "y": 27.25 + "x": 79.875, + "y": 80 } }, "tilemap.tmx#tileset": { "scaleInDock": 1 }, + "tilemap.tmx#tileset-embedded": { + "scaleInDock": 1 + }, "tileset.tsx": { "scaleInDock": 1, "scaleInEditor": 1 @@ -36,13 +53,15 @@ "map.tileWidth": 16, "map.width": 10, "openFiles": [ - "tileset.tsx", - "tilemap.tmx" + "tilemap.tmx", + "D:/Projects/csharp/TiledCSPlus/TiledCSPlus.Example/assets/tilemap.tmx", + "tileset.tsx" ], "project": "TiledCSPlus_test.tiled-project", "recentFiles": [ + "tilemap.tmx", "tileset.tsx", - "tilemap.tmx" + "D:/Projects/csharp/TiledCSPlus/TiledCSPlus.Example/assets/tilemap.tmx" ], "tileset.embedInMap": true, "tileset.lastUsedFilter": "Tiled tileset files (*.tsx *.xml)", diff --git a/TiledCSPlus.Test/assets/tilemap.tmx b/TiledCSPlus.Test/assets/tilemap.tmx index 8b6c280..9a5aa44 100644 --- a/TiledCSPlus.Test/assets/tilemap.tmx +++ b/TiledCSPlus.Test/assets/tilemap.tmx @@ -1,9 +1,15 @@ - + + + + - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAABAAAAAQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAQAAAAEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + + + diff --git a/TiledCSPlus/TiledMap.cs b/TiledCSPlus/TiledMap.cs index 519b25f..e545c29 100644 --- a/TiledCSPlus/TiledMap.cs +++ b/TiledCSPlus/TiledMap.cs @@ -99,6 +99,11 @@ public class TiledMap /// public Color BackgroundColor { get; internal set; } + /// + /// Returns tilesets embedded in the map + /// + public Dictionary EmbeddedTilesets { get; internal set; } + /// /// Returns an empty instance of TiledMap /// @@ -158,31 +163,32 @@ public void ParseXml(string xml) var nodeMap = document.SelectSingleNode("map"); var nodesProperty = nodeMap.SelectNodes("properties/property"); - var nodesLayer = nodeMap.SelectNodes("layer"); - var nodesImageLayer = nodeMap.SelectNodes("imagelayer"); - var nodesObjectGroup = nodeMap.SelectNodes("objectgroup"); + var nodesLayer = nodeMap.SelectNodes("layer | objectgroup | imagelayer"); var nodesTileset = nodeMap.SelectNodes("tileset"); var nodesGroup = nodeMap.SelectNodes("group"); var attrParallaxOriginX = nodeMap.Attributes["parallaxoriginx"]; var attrParallaxOriginY = nodeMap.Attributes["parallaxoriginy"]; + var attrBackgroundColor = nodeMap.Attributes["backgroundcolor"]; TiledVersion = nodeMap.Attributes["tiledversion"].Value; Orientation = nodeMap.Attributes["orientation"].Value; RenderOrder = nodeMap.Attributes["renderorder"].Value; - BackgroundColor = ParseColor(nodeMap.Attributes["backgroundcolor"]?.Value); Infinite = nodeMap.Attributes["infinite"].Value == "1"; + EmbeddedTilesets = new Dictionary(); Width = int.Parse(nodeMap.Attributes["width"].Value); Height = int.Parse(nodeMap.Attributes["height"].Value); TileWidth = int.Parse(nodeMap.Attributes["tilewidth"].Value); TileHeight = int.Parse(nodeMap.Attributes["tileheight"].Value); + if (nodesProperty != null) Properties = ParseProperties(nodesProperty); if (nodesTileset != null) Tilesets = ParseTilesets(nodesTileset); - if (nodesLayer != null) Layers = ParseLayers(nodesLayer, nodesObjectGroup, nodesImageLayer); + if (nodesLayer != null) Layers = ParseLayers(nodesLayer); if (nodesGroup != null) Groups = ParseGroups(nodesGroup); if (attrParallaxOriginX != null) ParallaxOriginX = float.Parse(attrParallaxOriginX.Value, CultureInfo.InvariantCulture); if (attrParallaxOriginY != null) ParallaxOriginY = float.Parse(attrParallaxOriginY.Value, CultureInfo.InvariantCulture); + if (attrBackgroundColor != null) BackgroundColor = ParseColor(attrBackgroundColor.Value); } catch (Exception ex) { @@ -230,11 +236,26 @@ private TiledMapTileset[] ParseTilesets(XmlNodeList nodeList) foreach (XmlNode node in nodeList) { - var tileset = new TiledMapTileset(); - tileset.FirstGid = int.Parse(node.Attributes["firstgid"].Value); - tileset.Source = node.Attributes["source"]?.Value; - - result.Add(tileset); + if (node.Attributes["source"] == null) + { + //tilemap is an embedded tilemap + TiledTileset tileset = new TiledTileset(); + tileset.ParseXml(node.OuterXml); + int firstgid = int.Parse(node.Attributes["firstgid"].Value); + EmbeddedTilesets.Add(firstgid, tileset); + var maptileset = new TiledMapTileset(); + maptileset.FirstGid = int.Parse(node.Attributes["firstgid"].Value); + maptileset.IsTilesetEmbedded = true; + result.Add(maptileset); + } + else + { + var tileset = new TiledMapTileset(); + tileset.FirstGid = int.Parse(node.Attributes["firstgid"].Value); + tileset.Source = node.Attributes["source"]?.Value; + tileset.IsTilesetEmbedded = false; + result.Add(tileset); + } } return result.ToArray(); @@ -248,9 +269,7 @@ private TiledGroup[] ParseGroups(XmlNodeList nodeListGroups) { var nodesProperty = node.SelectNodes("properties/property"); var nodesGroup = node.SelectNodes("group"); - var nodesLayer = node.SelectNodes("layer"); - var nodesObjectGroup = node.SelectNodes("objectgroup"); - var nodesImageLayer = node.SelectNodes("imagelayer"); + var nodesLayer = node.SelectNodes("layer | objectgroup | imagelayer"); var attrVisible = node.Attributes["visible"]; var attrLocked = node.Attributes["locked"]; @@ -262,7 +281,7 @@ private TiledGroup[] ParseGroups(XmlNodeList nodeListGroups) if (attrLocked != null) tiledGroup.Locked = attrLocked.Value == "1"; if (nodesProperty != null) tiledGroup.Properties = ParseProperties(nodesProperty); if (nodesGroup != null) tiledGroup.Groups = ParseGroups(nodesGroup); - if (nodesLayer != null) tiledGroup.Layers = ParseLayers(nodesLayer, nodesObjectGroup, nodesImageLayer); + if (nodesLayer != null) tiledGroup.Layers = ParseLayers(nodesLayer); result.Add(tiledGroup); } @@ -270,23 +289,25 @@ private TiledGroup[] ParseGroups(XmlNodeList nodeListGroups) return result.ToArray(); } - private TiledLayer[] ParseLayers(XmlNodeList nodesLayer, XmlNodeList nodesObjectGroup, XmlNodeList nodesImageLayer) + private TiledLayer[] ParseLayers(XmlNodeList nodesLayer) { var result = new List(); - foreach (XmlNode node in nodesLayer) { - result.Add(ParseLayer(node, TiledLayerType.TileLayer)); - } - - foreach (XmlNode node in nodesObjectGroup) - { - result.Add(ParseLayer(node, TiledLayerType.ObjectLayer)); - } - - foreach (XmlNode node in nodesImageLayer) - { - result.Add(ParseLayer(node, TiledLayerType.ImageLayer)); + switch (node.Name) + { + case "layer": + result.Add(ParseLayer(node, TiledLayerType.TileLayer)); + break; + case "objectgroup": + result.Add(ParseLayer(node, TiledLayerType.ObjectLayer)); + break; + case "imagelayer": + result.Add(ParseLayer(node, TiledLayerType.ImageLayer)); + break; + default: + throw new TiledException($"Unknown layer type: {node.Name}"); + } } return result.ToArray(); diff --git a/TiledCSPlus/TiledModels.cs b/TiledCSPlus/TiledModels.cs index 08bc41a..e6fae5f 100644 --- a/TiledCSPlus/TiledModels.cs +++ b/TiledCSPlus/TiledModels.cs @@ -21,33 +21,10 @@ public Vector2(float x = 0, float y = 0) this.Y = y; } - public static bool operator ==(Vector2 c1, Vector2 c2) - { - return c1.X == c2.X && c1.Y == c2.Y; - } - - public static bool operator !=(Vector2 c1, Vector2 c2) - { - return c1.X != c2.X || c1.Y != c2.Y; - } - public bool Equals(Vector2 other) { return X.Equals(other.X) && Y.Equals(other.Y); } - - public override bool Equals(object? obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; - return Equals((Vector2)obj); - } - - public override int GetHashCode() - { - return HashCode.Combine(X, Y); - } } /// @@ -63,15 +40,6 @@ public Size(float width = 0, float height = 0) this.Width = width; this.Height = height; } - public static bool operator ==(Size c1, Size c2) - { - return c1.Width == c2.Width && c1.Height == c2.Height; - } - - public static bool operator !=(Size c1, Size c2) - { - return c1.Width != c2.Width || c1.Height != c2.Height; - } public bool Equals(Size? other) { @@ -112,18 +80,6 @@ public Color(byte r, byte g, byte b, byte a = 255) this.A = a; } - - - public static bool operator ==(Color c1, Color c2) - { - return c1.R == c2.R && c1.G == c2.G && c1.B == c2.B && c1.A == c2.A; - } - - public static bool operator !=(Color c1, Color c2) - { - return c1.R != c2.R || c1.G != c2.G || c1.B != c2.B || c1.A != c2.A; - } - public bool Equals(Color? other) { return R.Equals(other.R) && G.Equals(other.G) && B.Equals(other.B) && A.Equals(other.A); @@ -140,6 +96,11 @@ public class TiledMapTileset /// public int FirstGid { get; internal set; } + /// + /// Returns true if tileset is embedded in map + /// + public bool IsTilesetEmbedded { get; internal set; } + /// /// The tsx file path as defined in the map file itself /// diff --git a/TiledCSPlus/TiledTileset.cs b/TiledCSPlus/TiledTileset.cs index fcbe3dc..86e4ebc 100644 --- a/TiledCSPlus/TiledTileset.cs +++ b/TiledCSPlus/TiledTileset.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.Drawing; using System.Globalization; using System.IO; +using System.Numerics; using System.Xml; namespace TiledCSPlus @@ -133,7 +135,9 @@ public void ParseXml(string xml) var attrSpacing = nodeTileset.Attributes["spacing"]; var attrClass = nodeTileset.Attributes["class"]; - TiledVersion = nodeTileset.Attributes["tiledversion"].Value; + TiledVersion = nodeTileset.Attributes["tiledversion"] != null + ? nodeTileset.Attributes["tiledversion"].Value + : ""; Name = nodeTileset.Attributes["name"]?.Value; TileWidth = int.Parse(nodeTileset.Attributes["tilewidth"].Value); TileHeight = int.Parse(nodeTileset.Attributes["tileheight"].Value);