コード例 #1
0
        public static List <TmxLayerNode> ListFromXml(XElement xmlRoot, TmxLayerNode parent, TmxMap tmxMap)
        {
            List <TmxLayerNode> list = new List <TmxLayerNode>();

            foreach (XElement item in xmlRoot.Elements())
            {
                TmxLayerNode tmxLayerNode = null;
                if (item.Name == (XName)"layer" || item.Name == (XName)"imagelayer")
                {
                    tmxLayerNode = TmxLayer.FromXml(item, parent, tmxMap);
                }
                else if (item.Name == (XName)"objectgroup")
                {
                    tmxLayerNode = TmxObjectGroup.FromXml(item, parent, tmxMap);
                }
                else if (item.Name == (XName)"group")
                {
                    tmxLayerNode = TmxGroupLayer.FromXml(item, parent, tmxMap);
                }
                if (tmxLayerNode != null && tmxLayerNode.Visible && tmxLayerNode.Ignore != IgnoreSettings.True)
                {
                    list.Add(tmxLayerNode);
                }
            }
            return(list);
        }
コード例 #2
0
        public static List <TmxLayerNode> ListFromXml(XElement xmlRoot, TmxLayerNode parent, TmxMap tmxMap)
        {
            List <TmxLayerNode> nodes = new List <TmxLayerNode>();

            foreach (var xmlNode in xmlRoot.Elements())
            {
                TmxLayerNode layerNode = null;

                if (xmlNode.Name == "layer" || xmlNode.Name == "imagelayer")
                {
                    layerNode = TmxLayer.FromXml(xmlNode, parent, tmxMap);
                }
                else if (xmlNode.Name == "objectgroup")
                {
                    layerNode = TmxObjectGroup.FromXml(xmlNode, parent, tmxMap);
                }
                else if (xmlNode.Name == "group")
                {
                    layerNode = TmxGroupLayer.FromXml(xmlNode, parent, tmxMap);
                }

                // If the layer is visible then add it to our list
                if (layerNode != null && layerNode.Visible)
                {
                    nodes.Add(layerNode);
                }
            }

            return(nodes);
        }
コード例 #3
0
ファイル: TmxLayer.cs プロジェクト: dayfox5317/tiled2unity
 private void BuildCollisionLayers_ByObjectType()
 {
     for (int i = 0; i < Data.Chunks.Count; i++)
     {
         TmxChunk tmxChunk = Data.Chunks[i];
         for (int j = 0; j < tmxChunk.TileIds.Count; j++)
         {
             uint num = tmxChunk.TileIds[j];
             if (num != 0)
             {
                 uint tileIdWithoutFlags = TmxMath.GetTileIdWithoutFlags(num);
                 foreach (TmxObject @object in base.ParentMap.Tiles[tileIdWithoutFlags].ObjectGroup.Objects)
                 {
                     if (@object is TmxHasPoints)
                     {
                         TmxLayer tmxLayer = CollisionLayers.Find((TmxLayer l) => string.Compare(l.Name, @object.Type, true) == 0);
                         if (tmxLayer == null)
                         {
                             tmxLayer = new TmxLayer(null, base.ParentMap);
                             CollisionLayers.Add(tmxLayer);
                             tmxLayer.Name       = @object.Type;
                             tmxLayer.Offset     = base.Offset;
                             tmxLayer.Width      = Width;
                             tmxLayer.Height     = Height;
                             tmxLayer.Ignore     = base.Ignore;
                             tmxLayer.Properties = base.Properties;
                             tmxLayer.Data       = Data.MakeEmptyCopy(tmxLayer);
                         }
                         tmxLayer.Data.Chunks[i].TileIds[j] = num;
                     }
                 }
             }
         }
     }
 }
コード例 #4
0
ファイル: TmxMap.Xml.cs プロジェクト: zachwhite/Tiled2Unity
        private void ParseAllLayers(XDocument doc)
        {
            Program.WriteLine("Parsing layer elements ...");
            var layers = (from item in doc.Descendants("layer")
                          select item).ToList();

            foreach (var lay in layers)
            {
                TmxLayer tmxLayer = TmxLayer.FromXml(lay, this.Layers.Count);

                // Layers may be ignored
                if (tmxLayer.Properties.GetPropertyValueAsBoolean("unity:ignore", false) == true)
                {
                    // We don't care about this layer
                    Program.WriteLine("Ignoring layer due to unity:ignore property: {0}", tmxLayer.UniqueName);
                    continue;
                }

                int maxVertices = 65535;
                int numVertices = (from tileId in tmxLayer.TileIds
                                   where tileId != 0
                                   select tileId).Count() * 4;
                if (numVertices > maxVertices)
                {
                    Program.WriteWarning("Layer '{0}' will have more than {1} vertices (vertex count = {2}) and will be split into {3} parts by Unity.",
                                         tmxLayer.UniqueName,
                                         maxVertices,
                                         numVertices,
                                         numVertices / maxVertices + 1);
                }

                this.Layers.Add(tmxLayer);
            }
        }
コード例 #5
0
        private List <XElement> CreateMeshElementsForLayer(TmxLayer layer)
        {
            List <XElement> xmlMeshes = new List <XElement>();

            foreach (TmxMesh mesh in layer.Meshes)
            {
                XElement xmlMesh = new XElement("GameObject",
                                                new XAttribute("name", mesh.ObjectName),
                                                new XAttribute("copy", mesh.UniqueMeshName),
                                                new XAttribute("sortingLayerName", layer.SortingLayerName),
                                                new XAttribute("sortingOrder", layer.SortingOrder),
                                                new XAttribute("opacity", layer.Opacity));
                xmlMeshes.Add(xmlMesh);

                if (mesh.FullAnimationDurationMs > 0)
                {
                    XElement xmlAnimation = new XElement("TileAnimator",
                                                         new XAttribute("startTimeMs", mesh.StartTimeMs),
                                                         new XAttribute("durationMs", mesh.DurationMs),
                                                         new XAttribute("fullTimeMs", mesh.FullAnimationDurationMs));
                    xmlMesh.Add(xmlAnimation);
                }
            }

            return(xmlMeshes);
        }
コード例 #6
0
ファイル: TmxMesh.cs プロジェクト: mdhausman/Tiled2Unity
        // Splits a layer into TmxMesh instances
        public static List <TmxMesh> ListFromTmxLayer(TmxLayer layer)
        {
            List <TmxMesh> meshes = new List <TmxMesh>();

            for (int i = 0; i < layer.TileIds.Count(); ++i)
            {
                // Copy the tile unto the mesh that uses the same image
                // (In other words, we are grouping tiles by images into a mesh)
                uint    tileId = layer.TileIds[i];
                TmxTile tile   = layer.TmxMap.GetTileFromTileId(tileId);
                if (tile == null)
                {
                    continue;
                }

                int timeMs = 0;
                foreach (var frame in tile.Animation.Frames)
                {
                    uint frameTileId = frame.GlobalTileId;

                    // Have to put any rotations/flipping from the source tile into this one
                    frameTileId |= (tileId & TmxMath.FLIPPED_HORIZONTALLY_FLAG);
                    frameTileId |= (tileId & TmxMath.FLIPPED_VERTICALLY_FLAG);
                    frameTileId |= (tileId & TmxMath.FLIPPED_DIAGONALLY_FLAG);

                    // Find a mesh to stick this tile into (if it exists)
                    TmxMesh mesh = meshes.Find(m => m.CanAddFrame(tile, timeMs, frame.DurationMs));
                    if (mesh == null)
                    {
                        // Create a new mesh and add it to our list
                        mesh                = new TmxMesh();
                        mesh.TileIds        = new uint[layer.TileIds.Count()];
                        mesh.UniqueMeshName = String.Format("mesh_{0}", layer.TmxMap.GetUniqueId().ToString("D4"));
                        mesh.TmxImage       = tile.TmxImage;

                        // Keep track of the timing for this mesh (non-animating meshes will have a start time and duration of 0)
                        mesh.StartTimeMs             = timeMs;
                        mesh.DurationMs              = frame.DurationMs;
                        mesh.FullAnimationDurationMs = tile.Animation.TotalTimeMs;

                        mesh.ObjectName = Path.GetFileNameWithoutExtension(tile.TmxImage.AbsolutePath);
                        if (mesh.DurationMs != 0)
                        {
                            // Decorate the name a bit with some animation details for the frame
                            mesh.ObjectName += string.Format("[{0}-{1}]", timeMs, timeMs + mesh.DurationMs);
                        }

                        meshes.Add(mesh);
                    }

                    // This mesh contains this tile
                    mesh.AddTile(i, frameTileId);

                    // Advance time
                    timeMs += frame.DurationMs;
                }
            }

            return(meshes);
        }
コード例 #7
0
        public void VisitTileLayer(TmxLayer tileLayer)
        {
            // Tile layer does render something and therefore increases draw order index
            tileLayer.DrawOrderIndex = this.drawOrderIndex++;

            // Either inherit depth buffer index of parent or advance
            tileLayer.DepthBufferIndex = (tileLayer.ParentNode != null) ? tileLayer.ParentNode.DepthBufferIndex : this.depthBufferIndex++;
        }
コード例 #8
0
        public void VisitTileLayer(TmxLayer tileLayer)
        {
            // Tile layer does render something and therefore increases draw order index
            tileLayer.DrawOrderIndex = this.drawOrderIndex++;

            // Children don't have a depth buffer index. Their parent sets the depth.
            tileLayer.DepthBufferIndex = (tileLayer.ParentNode != null) ? 0 : this.depthBufferIndex++;
        }
コード例 #9
0
ファイル: TmxMesh.cs プロジェクト: knunery/Tiled2Unity
        // Splits a layer into TmxMesh instances
        public static List<TmxMesh> ListFromTmxLayer(TmxLayer layer)
        {
            List<TmxMesh> meshes = new List<TmxMesh>();

            for (int i = 0; i < layer.TileIds.Count(); ++i)
            {
                // Copy the tile unto the mesh that uses the same image
                // (In other words, we are grouping tiles by images into a mesh)
                uint tileId = layer.TileIds[i];
                TmxTile tile = layer.TmxMap.GetTileFromTileId(tileId);
                if (tile == null)
                    continue;

                int timeMs = 0;
                foreach (var frame in tile.Animation.Frames)
                {
                    uint frameTileId = frame.GlobalTileId;

                    // Have to put any rotations/flipping from the source tile into this one
                    frameTileId |= (tileId & TmxMath.FLIPPED_HORIZONTALLY_FLAG);
                    frameTileId |= (tileId & TmxMath.FLIPPED_VERTICALLY_FLAG);
                    frameTileId |= (tileId & TmxMath.FLIPPED_DIAGONALLY_FLAG);

                    // Find a mesh to stick this tile into (if it exists)
                    TmxMesh mesh = meshes.Find(m => m.CanAddFrame(tile, timeMs, frame.DurationMs));
                    if (mesh == null)
                    {
                        // Create a new mesh and add it to our list
                        mesh = new TmxMesh();
                        mesh.TileIds = new uint[layer.TileIds.Count()];
                        mesh.UniqueMeshName = String.Format("mesh_{0}", layer.TmxMap.GetUniqueId().ToString("D4"));
                        mesh.TmxImage = tile.TmxImage;

                        // Keep track of the timing for this mesh (non-animating meshes will have a start time and duration of 0)
                        mesh.StartTimeMs = timeMs;
                        mesh.DurationMs = frame.DurationMs;
                        mesh.FullAnimationDurationMs = tile.Animation.TotalTimeMs;

                        mesh.ObjectName = Path.GetFileNameWithoutExtension(tile.TmxImage.AbsolutePath);
                        if (mesh.DurationMs != 0)
                        {
                            // Decorate the name a bit with some animation details for the frame
                            mesh.ObjectName += string.Format("[{0}-{1}]", timeMs, timeMs + mesh.DurationMs);
                        }

                        meshes.Add(mesh);
                    }

                    // This mesh contains this tile
                    mesh.AddTile(i, frameTileId);

                    // Advance time
                    timeMs += frame.DurationMs;
                }
            }

            return meshes;
        }
コード例 #10
0
        public static TmxData FromDataXml(XElement xml, TmxLayer parentLayer)
        {
            TmxData tmxData = new TmxData(parentLayer);

            tmxData.Encoding    = TmxHelper.GetAttributeAsEnum(xml, "encoding", DataEncoding.Xml);
            tmxData.Compression = TmxHelper.GetAttributeAsEnum(xml, "compression", DataCompression.None);
            tmxData.Chunks      = TmxChunk.ListFromDataXml(xml, tmxData);
            return(tmxData);
        }
コード例 #11
0
ファイル: TmxMesh.cs プロジェクト: dayfox5317/tiled2unity
        public static List <TmxMesh> ListFromTmxLayer(TmxLayer layer)
        {
            List <TmxMesh> list = new List <TmxMesh>();

            foreach (TmxChunk chunk in layer.Data.Chunks)
            {
                list.AddRange(ListFromTmxChunk(chunk));
            }
            return(list);
        }
コード例 #12
0
        public TmxData MakeEmptyCopy(TmxLayer parent)
        {
            TmxData data = new TmxData(parent);

            data.Encoding    = Encoding;
            data.Compression = Compression;
            data.Chunks      = (from c in Chunks
                                select c.MakeEmptyCopy(data)).ToList();
            return(data);
        }
コード例 #13
0
        private XElement CreateCollisionElementForLayer(TmxLayer layer)
        {
            // Collision elements look like this
            // (Can also have EdgeCollider2Ds)
            //      <GameOject name="Collision">
            //        <PolygonCollider2D>
            //          <Path>list of points</Path>
            //          <Path>another list of points</Path>
            //        </PolygonCollider2D>
            //      </GameOject>

            LayerClipper.TransformPointFunc xfFunc =
                delegate(float x, float y)
            {
                // Transform point to Unity space
                PointF pointUnity3d       = PointFToUnityVector_NoScale(new PointF(x, y));
                ClipperLib.IntPoint point = new ClipperLib.IntPoint(pointUnity3d.X, pointUnity3d.Y);
                return(point);
            };

            LayerClipper.ProgressFunc progFunc =
                delegate(string prog)
            {
                Program.WriteLine(prog);
            };

            ClipperLib.PolyTree solution = LayerClipper.ExecuteClipper(this.tmxMap, layer, xfFunc, progFunc);

            // Add our polygon and edge colliders
            List <XElement> polyColliderElements = new List <XElement>();

            if (layer.IsExportingConvexPolygons())
            {
                AddPolygonCollider2DElements_Convex(solution, polyColliderElements);
            }
            else
            {
                AddPolygonCollider2DElements_Complex(solution, polyColliderElements);
            }

            AddEdgeCollider2DElements(ClipperLib.Clipper.OpenPathsFromPolyTree(solution), polyColliderElements);

            if (polyColliderElements.Count() == 0)
            {
                // No collisions on this layer
                return(null);
            }

            XElement gameObjectCollision =
                new XElement("GameObject",
                             new XAttribute("name", "Collision"),
                             polyColliderElements);

            return(gameObjectCollision);
        }
コード例 #14
0
        private StringWriter BuildWavefrontStringForLayerMesh(TmxLayer layer, TmxMesh mesh, IEnumerable <int> horizontalRange, IEnumerable <int> verticalRange)
        {
            Logger.WriteVerbose("Building mesh obj file for '{0}'", mesh.UniqueMeshName);
            GenericListDatabase <Vertex3> vertexDatabase = new GenericListDatabase <Vertex3>();
            HashIndexOf <PointF>          uvDatabase     = new HashIndexOf <PointF>();
            StringBuilder faces = new StringBuilder();

            foreach (int y in verticalRange)
            {
                foreach (int x in horizontalRange)
                {
                    int  tileIndex = layer.GetTileIndex(x, y);
                    uint tileId    = mesh.GetTileIdAt(tileIndex);

                    // Skip blank tiles
                    if (tileId == 0)
                    {
                        continue;
                    }

                    TmxTile tile = this.tmxMap.Tiles[TmxMath.GetTileIdWithoutFlags(tileId)];

                    // What are the vertex and texture coorindates of this face on the mesh?
                    var position = this.tmxMap.GetMapPositionAt(x, y, tile);
                    var vertices = CalculateFaceVertices(position, tile.TileSize);

                    // If we're using depth shaders then we'll need to set a depth value of this face
                    float depth_z = 0.0f;
                    if (Tiled2Unity.Settings.DepthBufferEnabled)
                    {
                        depth_z = CalculateFaceDepth(position.Y + tmxMap.TileHeight, tmxMap.MapSizeInPixels.Height);
                    }

                    FaceVertices faceVertices = new FaceVertices {
                        Vertices = vertices, Depth_z = depth_z
                    };

                    // Is the tile being flipped or rotated (needed for texture cooridinates)
                    bool flipDiagonal   = TmxMath.IsTileFlippedDiagonally(tileId);
                    bool flipHorizontal = TmxMath.IsTileFlippedHorizontally(tileId);
                    bool flipVertical   = TmxMath.IsTileFlippedVertically(tileId);
                    var  uvs            = CalculateFaceTextureCoordinates(tile, flipDiagonal, flipHorizontal, flipVertical);

                    // Adds vertices and uvs to the database as we build the face strings
                    string v0 = String.Format("{0}/{1}/1", vertexDatabase.AddToDatabase(faceVertices.V0) + 1, uvDatabase.Add(uvs[0]) + 1);
                    string v1 = String.Format("{0}/{1}/1", vertexDatabase.AddToDatabase(faceVertices.V1) + 1, uvDatabase.Add(uvs[1]) + 1);
                    string v2 = String.Format("{0}/{1}/1", vertexDatabase.AddToDatabase(faceVertices.V2) + 1, uvDatabase.Add(uvs[2]) + 1);
                    string v3 = String.Format("{0}/{1}/1", vertexDatabase.AddToDatabase(faceVertices.V3) + 1, uvDatabase.Add(uvs[3]) + 1);
                    faces.AppendFormat("f {0} {1} {2} {3}\n", v0, v1, v2, v3);
                }
            }

            // We have all the data we need to build the wavefront file format
            return(CreateWavefrontWriter(mesh, vertexDatabase, uvDatabase, faces));
        }
コード例 #15
0
        private void AddTileLayerToElement(TmxLayer tileLayer, XElement xmlRoot)
        {
            XElement xmlLayer = new XElement("GameObject");

            xmlLayer.SetAttributeValue("name", tileLayer.Name);

            // Figure out the offset for this layer
            PointF offset  = PointFToUnityVector(tileLayer.Offset);
            float  depth_z = CalculateLayerDepth(tileLayer);

            xmlLayer.SetAttributeValue("x", offset.X);
            xmlLayer.SetAttributeValue("y", offset.Y);
            xmlLayer.SetAttributeValue("z", depth_z);

            // Add a TileLayer component
            {
                XElement layerComponent = new XElement("TileLayer",
                                                       new XAttribute("opacity", tileLayer.Opacity),
                                                       new XAttribute("offsetX", tileLayer.Offset.X),
                                                       new XAttribute("offsetY", tileLayer.Offset.Y));

                xmlLayer.Add(layerComponent);
            }

            // Add a Terrain component
            XElement terrainComponent = new XElement("Terrain", CreateTerrainDataForLayer(tileLayer));

            xmlLayer.Add(terrainComponent);

            if (tileLayer.Ignore != TmxLayer.IgnoreSettings.Visual)
            {
                // Submeshes for the layer (layer+material)
                var meshElements = CreateMeshElementsForLayer(tileLayer);
                xmlLayer.Add(meshElements);
            }

            // Collision data for the layer
            if (tileLayer.Ignore != TmxLayer.IgnoreSettings.Collision)
            {
                foreach (var collisionLayer in tileLayer.CollisionLayers)
                {
                    var collisionElements = CreateCollisionElementForLayer(collisionLayer);
                    xmlLayer.Add(collisionElements);
                }
            }

            // Assign and special properties
            AssignUnityProperties(tileLayer, xmlLayer, PrefabContext.TiledLayer);
            AssignTiledProperties(tileLayer, xmlLayer);

            // Finally, add the layer to our root
            xmlRoot.Add(xmlLayer);
        }
コード例 #16
0
 private void DrawColliders(Graphics g)
 {
     for (int l = 0; l < this.tmxMap.Layers.Count; ++l)
     {
         TmxLayer layer = this.tmxMap.Layers[l];
         if (layer.Visible == true && IsLayerEnabled(layer.DefaultName))
         {
             Color lineColor = this.preferencesForm.GetLayerColor(layer.DefaultName);
             Color polyColor = Color.FromArgb(128, lineColor);
             DrawLayerColliders(g, layer, polyColor, lineColor);
         }
     }
 }
コード例 #17
0
        private void DrawLayerColliders(Graphics g, TmxLayer layer, Color polyColor, Color lineColor)
        {
            LayerClipper.TransformPointFunc xfFunc   = (x, y) => new ClipperLib.IntPoint(x, y);
            LayerClipper.ProgressFunc       progFunc = (prog) => { }; // do nothing

            ClipperLib.PolyTree solution = LayerClipper.ExecuteClipper(this.tmxMap, layer, xfFunc, progFunc);

            float inverseScale = 1.0f / this.scale;

            if (inverseScale > 1)
            {
                inverseScale = 1;
            }

            using (GraphicsPath path = new GraphicsPath())
                using (Pen pen = new Pen(lineColor, 2.0f * inverseScale))
                    using (Brush brush = new HatchBrush(HatchStyle.Percent60, polyColor, Color.Transparent))
                    {
                        pen.Alignment = PenAlignment.Inset;

                        // Draw all closed polygons
                        // First, add them to the path
                        // (But are we using convex polygons are complex polygons?
                        var polygons = layer.IsExportingConvexPolygons() ? LayerClipper.SolutionPolygons_Simple(solution) : LayerClipper.SolutionPolygons_Complex(solution);
                        foreach (var pointfArray in polygons)
                        {
                            path.AddPolygon(pointfArray);
                        }

                        // Then, fill and draw the path full of polygons
                        if (path.PointCount > 0)
                        {
                            g.FillPath(brush, path);
                            g.DrawPath(pen, path);
                        }

                        // Draw all lines (open polygons)
                        path.Reset();
                        foreach (var points in ClipperLib.Clipper.OpenPathsFromPolyTree(solution))
                        {
                            var pointfs = points.Select(pt => new PointF(pt.X, pt.Y));
                            path.StartFigure();
                            path.AddLines(pointfs.ToArray());
                        }
                        if (path.PointCount > 0)
                        {
                            g.DrawPath(pen, path);
                        }
                    }
        }
コード例 #18
0
        private string CreateTerrainDataForLayer(TmxLayer layer)
        {
            StringBuilder result = new StringBuilder();

            for (int y = 0; y < layer.Height; y += 1)
            {
                for (int x = 0; x < layer.Width; x += 1)
                {
                    uint terrainId = layer.GetTileIdAt(x, y);
                    result.Append(terrainId);
                    result.Append(',');
                }
            }
            return(result.ToString());
        }
コード例 #19
0
        private void BuildCollisionLayers_ByObjectType()
        {
            // Find all tiles with collisions on them and put them into a "Collision Layer" of the same type
            for (int t = 0; t < this.TileIds.Length; ++t)
            {
                uint rawTileId = this.TileIds[t];
                if (rawTileId == 0)
                {
                    continue;
                }

                uint    tileId  = TmxMath.GetTileIdWithoutFlags(rawTileId);
                TmxTile tmxTile = this.TmxMap.Tiles[tileId];

                foreach (TmxObject colliderObject in tmxTile.ObjectGroup.Objects)
                {
                    if ((colliderObject is TmxHasPoints) == false)
                    {
                        continue;
                    }

                    // We have a collider object on the tile
                    // Add the tile to the Collision Layer of the matching type
                    // Or, create a new Collision Layer of this type to add this tile to
                    TmxLayer collisionLayer = this.CollisionLayers.Find(l => String.Compare(l.Name, colliderObject.Type, true) == 0);
                    if (collisionLayer == null)
                    {
                        // Create a new Collision Layer
                        collisionLayer = new TmxLayer(null, this.TmxMap);
                        this.CollisionLayers.Add(collisionLayer);

                        // The new Collision Layer has the name of the collider object and empty tiles (they will be filled with tiles that have matching collider objects)
                        collisionLayer.Name    = colliderObject.Type;
                        collisionLayer.TileIds = new uint[this.TileIds.Length];

                        // Copy over some stuff from parent layer that we need for creating collisions
                        collisionLayer.Offset     = this.Offset;
                        collisionLayer.Width      = this.Width;
                        collisionLayer.Height     = this.Height;
                        collisionLayer.Ignore     = this.Ignore;
                        collisionLayer.Properties = this.Properties;
                    }

                    // Add the tile to this collision layer
                    collisionLayer.TileIds[t] = rawTileId;
                }
            }
        }
コード例 #20
0
ファイル: TmxLayer.cs プロジェクト: dayfox5317/tiled2unity
        public static TmxLayer FromXml(XElement elem, TmxLayerNode parent, TmxMap tmxMap)
        {
            TmxLayer tmxLayer = new TmxLayer(parent, tmxMap);

            tmxLayer.FromXmlInternal(elem);
            if (elem.Name == (XName)"layer")
            {
                tmxLayer.ParseLayerXml(elem);
            }
            else if (elem.Name == (XName)"imagelayer")
            {
                tmxLayer.ParseImageLayerXml(elem);
            }
            tmxLayer.Meshes = TmxMesh.ListFromTmxLayer(tmxLayer);
            tmxLayer.BuildCollisionLayers();
            return(tmxLayer);
        }
コード例 #21
0
        private XElement CreateCollisionElementForLayer(TmxLayer layer)
        {
            // Collision elements look like this
            // (Can also have EdgeCollider2Ds)
            //      <GameOject name="Collision">
            //        <PolygonCollider2D>
            //          <Path>list of points</Path>
            //          <Path>another list of points</Path>
            //        </PolygonCollider2D>
            //      </GameOject>

            LayerClipper.TransformPointFunc xfFunc =
                delegate(float x, float y)
                {
                    // Transform point to Unity space
                    Vector3D pointUnity3d = PointFToUnityVector_NoScale(new PointF(x, y));
                    IntPoint point = new IntPoint(pointUnity3d.X, pointUnity3d.Y);
                    return point;
                };

            LayerClipper.ProgressFunc progFunc =
                delegate(string prog)
                {
                    Program.WriteLine(prog);
                };

            ClipperLib.PolyTree solution = LayerClipper.ExecuteClipper(this.tmxMap, layer, xfFunc, progFunc);

            // Add our polygon and edge colliders
            List<XElement> polyColliderElements = new List<XElement>();
            AddPolygonCollider2DElements(Clipper.ClosedPathsFromPolyTree(solution), polyColliderElements);
            AddEdgeCollider2DElements(Clipper.OpenPathsFromPolyTree(solution), polyColliderElements);

            if (polyColliderElements.Count() == 0)
            {
                // No collisions on this layer
                return null;
            }

            XElement gameObjectCollision =
                new XElement("GameObject",
                    new XAttribute("name", "Collision"),
                    polyColliderElements);

            return gameObjectCollision;
        }
コード例 #22
0
        public static TmxLayer FromXml(XElement elem, int layerIndex)
        {
            Program.WriteVerbose(elem.ToString());
            TmxLayer tmxLayer = new TmxLayer();

            // Have to decorate layer names in order to force them into being unique
            // Also, can't have whitespace in the name because Unity will add underscores
            tmxLayer.DefaultName = TmxHelper.GetAttributeAsString(elem, "name");
            tmxLayer.UniqueName = String.Format("{0}_{1}", tmxLayer.DefaultName, layerIndex.ToString("D2")).Replace(" ", "_");

            tmxLayer.Visible = TmxHelper.GetAttributeAsInt(elem, "visible", 1) == 1;
            tmxLayer.Width = TmxHelper.GetAttributeAsInt(elem, "width");
            tmxLayer.Height = TmxHelper.GetAttributeAsInt(elem, "height");
            tmxLayer.Properties = TmxProperties.FromXml(elem);

            tmxLayer.ParseData(elem.Element("data"));

            return tmxLayer;
        }
コード例 #23
0
ファイル: TmxLayer.Xml.cs プロジェクト: zachwhite/Tiled2Unity
        public static TmxLayer FromXml(XElement elem, int layerIndex)
        {
            Program.WriteVerbose(elem.ToString());
            TmxLayer tmxLayer = new TmxLayer();

            // Have to decorate layer names in order to force them into being unique
            // Also, can't have whitespace in the name because Unity will add underscores
            tmxLayer.DefaultName = TmxHelper.GetAttributeAsString(elem, "name");
            tmxLayer.UniqueName  = String.Format("{0}_{1}", tmxLayer.DefaultName, layerIndex.ToString("D2")).Replace(" ", "_");

            tmxLayer.Visible    = TmxHelper.GetAttributeAsInt(elem, "visible", 1) == 1;
            tmxLayer.Width      = TmxHelper.GetAttributeAsInt(elem, "width");
            tmxLayer.Height     = TmxHelper.GetAttributeAsInt(elem, "height");
            tmxLayer.Properties = TmxProperties.FromXml(elem);

            tmxLayer.ParseData(elem.Element("data"));

            return(tmxLayer);
        }
コード例 #24
0
        private void DrawColliders(Graphics g)
        {
            for (int l = 0; l < this.tmxMap.Layers.Count; ++l)
            {
                TmxLayer layer = this.tmxMap.Layers[l];

                if (layer.Visible == true && layer.Ignore != TmxLayer.IgnoreSettings.Collision)
                {
                    foreach (TmxLayer collisionLayer in layer.CollisionLayers)
                    {
                        TmxObjectType type = this.tmxMap.ObjectTypes.GetValueOrDefault(collisionLayer.Name);

                        Color lineColor = type.Color;
                        Color polyColor = Color.FromArgb(128, lineColor);

                        DrawLayerColliders(g, collisionLayer, polyColor, lineColor);
                    }
                }
            }
        }
コード例 #25
0
        private List <XElement> CreateMeshElementsForLayer(TmxLayer layer)
        {
            // Mesh elements look like this:
            // <GameObject copy="LayerName+TilesetName" />
            // (The importer in Unity will look a submesh of that name and copy it to our prefab)
            // (This is complicated by potential tile animations now)

            var meshes = from rawTileId in layer.TileIds
                         where rawTileId != 0
                         let tileId                                                        = TmxMath.GetTileIdWithoutFlags(rawTileId)
                                                            let tile                       = this.tmxMap.Tiles[tileId]
                                                                                  let name = TiledMapExpoterUtils.UnityFriendlyMeshName(tmxMap, layer.UniqueName, Path.GetFileNameWithoutExtension(tile.TmxImage.Path))
                                                                                             group tile.Animation by name into meshGroup
                                                                                             select meshGroup;

            List <XElement> xmlMeshes = new List <XElement>();

            foreach (var m in meshes)
            {
                XElement xmlMesh = new XElement("GameObject", new XAttribute("copy", m.Key));

                // Do we have any animations?
                var animations = m.Distinct();
                foreach (var anim in animations)
                {
                    if (anim != null)
                    {
                        XElement xmlAnim = new XElement("TileAnimator");
                        foreach (var frame in anim.Frames)
                        {
                            xmlAnim.Add(new XElement("Frame", new XAttribute("vertex_z", frame.UniqueFrameId * Program.Vertex_ZScale), new XAttribute("duration", frame.DurationMs)));
                        }
                        xmlMesh.Add(xmlAnim);
                    }
                }

                xmlMeshes.Add(xmlMesh);
            }

            return(xmlMeshes);
        }
コード例 #26
0
        public static TmxProperties GetPropertiesWithTypeDefaults(TmxHasProperties hasProperties, TmxObjectTypes objectTypes)
        {
            TmxProperties tmxProperties = new TmxProperties();

            // Fill in all the default properties first
            // (Note: At the moment, only TmxObject has default properties it inherits from TmxObjectType)
            string objectTypeName = null;

            if (hasProperties is TmxObject)
            {
                TmxObject tmxObject = hasProperties as TmxObject;
                objectTypeName = tmxObject.Type;
            }
            else if (hasProperties is TmxLayer)
            {
                TmxLayer tmxLayer = hasProperties as TmxLayer;
                objectTypeName = tmxLayer.Name;
            }

            // If an object type has been found then copy over all the default values for properties
            TmxObjectType tmxObjectType = objectTypes.GetValueOrNull(objectTypeName);

            if (tmxObjectType != null)
            {
                foreach (TmxObjectTypeProperty tmxTypeProp in tmxObjectType.Properties.Values)
                {
                    tmxProperties.PropertyMap[tmxTypeProp.Name] = new TmxProperty()
                    {
                        Name = tmxTypeProp.Name, Type = tmxTypeProp.Type, Value = tmxTypeProp.Default
                    };
                }
            }

            // Now add all the object properties (which may override some of the default properties)
            foreach (TmxProperty tmxProp in hasProperties.Properties.PropertyMap.Values)
            {
                tmxProperties.PropertyMap[tmxProp.Name] = tmxProp;
            }

            return(tmxProperties);
        }
コード例 #27
0
        private void DrawLayerColliders(Graphics g, TmxLayer layer, Color polyColor, Color lineColor)
        {
            LayerClipper.TransformPointFunc xfFunc   = (x, y) => new ClipperLib.IntPoint(x, y);
            LayerClipper.ProgressFunc       progFunc = (prog) => { }; // do nothing

            ClipperLib.PolyTree solution = LayerClipper.ExecuteClipper(this.tmxMap, layer, xfFunc, progFunc);

            using (GraphicsPath path = new GraphicsPath())
                using (Pen pen = new Pen(lineColor, 1.0f))
                    using (Brush brush = new HatchBrush(HatchStyle.ForwardDiagonal, lineColor, polyColor))
                    {
                        pen.Alignment = PenAlignment.Inset;

                        // Draw all closed polygons
                        foreach (var points in ClipperLib.Clipper.ClosedPathsFromPolyTree(solution))
                        {
                            var pointfs = points.Select(pt => new PointF(pt.X, pt.Y));
                            path.AddPolygon(pointfs.ToArray());
                        }
                        if (path.PointCount > 0)
                        {
                            g.FillPath(brush, path);
                            g.DrawPath(pen, path);
                        }

                        // Draw all lines (open polygons)
                        path.Reset();
                        foreach (var points in ClipperLib.Clipper.OpenPathsFromPolyTree(solution))
                        {
                            var pointfs = points.Select(pt => new PointF(pt.X, pt.Y));
                            path.StartFigure();
                            path.AddLines(pointfs.ToArray());
                        }
                        if (path.PointCount > 0)
                        {
                            g.DrawPath(pen, path);
                        }
                    }
        }
コード例 #28
0
        private void ParseAllLayers(XDocument doc)
        {
            Logger.WriteLine("Parsing layer elements ...");

            // Parse "layer"s and "imagelayer"s
            var layers = (from item in doc.Descendants()
                          where (item.Name == "layer" || item.Name == "imagelayer")
                          select item).ToList();

            foreach (var lay in layers)
            {
                TmxLayer tmxLayer = TmxLayer.FromXml(lay, this);

                // Layers may be ignored
                if (tmxLayer.Ignore == TmxLayer.IgnoreSettings.True)
                {
                    // We don't care about this layer
                    Logger.WriteLine("Ignoring layer due to unity:ignore = True property: {0}", tmxLayer.Name);
                    continue;
                }

                this.Layers.Add(tmxLayer);
            }
        }
コード例 #29
0
        private void BuildBuildCollisionLayers_ByObjectType()
        {
            // Find all tiles with collisions on them and put them into a "Collision Layer" of the same type
            for (int t = 0; t < this.TileIds.Length; ++t)
            {
                uint rawTileId = this.TileIds[t];
                if (rawTileId == 0)
                    continue;

                uint tileId = TmxMath.GetTileIdWithoutFlags(rawTileId);
                TmxTile tmxTile = this.TmxMap.Tiles[tileId];

                foreach (TmxObject colliderObject in tmxTile.ObjectGroup.Objects)
                {
                    if ((colliderObject is TmxHasPoints) == false)
                        continue;

                    // We have a collider object on the tile
                    // Add the tile to the Collision Layer of the matching type
                    // Or, create a new Collision Layer of this type to add this tile to
                    TmxLayer collisionLayer = this.CollisionLayers.Find(l => String.Compare(l.Name, colliderObject.Type, true) == 0);
                    if (collisionLayer == null)
                    {
                        // Create a new Collision Layer
                        collisionLayer = new TmxLayer(this.TmxMap);
                        this.CollisionLayers.Add(collisionLayer);

                        // The new Collision Layer has the name of the collider object and empty tiles (they will be filled with tiles that have matching collider objects)
                        collisionLayer.Name = colliderObject.Type;
                        collisionLayer.TileIds = new uint[this.TileIds.Length];

                        // Copy over some stuff from parent layer that we need for creating collisions
                        collisionLayer.Offset = this.Offset;
                        collisionLayer.Width = this.Width;
                        collisionLayer.Height = this.Height;
                        collisionLayer.Ignore = this.Ignore;
                        collisionLayer.Properties = this.Properties;
                    }

                    // Add the tile to this collision layer
                    collisionLayer.TileIds[t] = rawTileId;
                }
            }
        }
コード例 #30
0
        private void DrawLayerColliders(Graphics g, TmxLayer layer, Color polyColor, Color lineColor)
        {
            LayerClipper.TransformPointFunc xfFunc = (x,y) => new ClipperLib.IntPoint(x, y);
            LayerClipper.ProgressFunc progFunc = (prog) => { }; // do nothing

            ClipperLib.PolyTree solution = LayerClipper.ExecuteClipper(this.tmxMap, layer, xfFunc, progFunc);

            float inverseScale = 1.0f / this.scale;
            if (inverseScale > 1)
                inverseScale = 1;

            using (GraphicsPath path = new GraphicsPath())
            using (Pen pen = new Pen(lineColor, 2.0f * inverseScale))
            using (Brush brush = new HatchBrush(HatchStyle.Percent60, polyColor, Color.Transparent))
            {
                pen.Alignment = PenAlignment.Inset;

                // Draw all closed polygons
                // First, add them to the path
                // (But are we using convex polygons are complex polygons?
                var polygons = layer.IsExportingConvexPolygons() ? LayerClipper.SolutionPolygons_Simple(solution) : LayerClipper.SolutionPolygons_Complex(solution);
                foreach (var pointfArray in polygons)
                {
                    path.AddPolygon(pointfArray);
                }

                // Then, fill and draw the path full of polygons
                if (path.PointCount > 0)
                {
                    g.FillPath(brush, path);
                    g.DrawPath(pen, path);
                }

                // Draw all lines (open polygons)
                path.Reset();
                foreach (var points in ClipperLib.Clipper.OpenPathsFromPolyTree(solution))
                {
                    var pointfs = points.Select(pt => new PointF(pt.X, pt.Y));
                    path.StartFigure();
                    path.AddLines(pointfs.ToArray());
                }
                if (path.PointCount > 0)
                {
                    g.DrawPath(pen, path);
                }
            }
        }
コード例 #31
0
 private int GetMaxTilesWide(TmxLayer layer)
 {
     return Math.Min(layer.Width, MaxPreviewTilesWide);
 }
コード例 #32
0
 private int GetMaxTilesHigh(TmxLayer layer)
 {
     return Math.Min(layer.Height, MaxPreviewTilesHigh);
 }
コード例 #33
0
        private List<XElement> CreateMeshElementsForLayer(TmxLayer layer)
        {
            List<XElement> xmlMeshes = new List<XElement>();

            foreach (TmxMesh mesh in layer.Meshes)
            {
                XElement xmlMesh = new XElement("GameObject",
                    new XAttribute("name", mesh.ObjectName),
                    new XAttribute("copy", mesh.UniqueMeshName),
                    new XAttribute("sortingLayerName", layer.SortingLayerName),
                    new XAttribute("sortingOrder", layer.SortingOrder),
                    new XAttribute("opacity", layer.Opacity));
                xmlMeshes.Add(xmlMesh);

                if (mesh.FullAnimationDurationMs > 0)
                {
                    XElement xmlAnimation = new XElement("TileAnimator",
                        new XAttribute("startTimeMs", mesh.StartTimeMs),
                        new XAttribute("durationMs", mesh.DurationMs),
                        new XAttribute("fullTimeMs", mesh.FullAnimationDurationMs));
                    xmlMesh.Add(xmlAnimation);
                }
            }

            return xmlMeshes;
        }
コード例 #34
0
ファイル: LayerClipper.cs プロジェクト: knunery/Tiled2Unity
        public static ClipperLib.PolyTree ExecuteClipper(TmxMap tmxMap, TmxLayer tmxLayer, TransformPointFunc xfFunc, ProgressFunc progFunc)
        {
            // The "fullClipper" combines the clipper results from the smaller pieces
            ClipperLib.Clipper fullClipper = new ClipperLib.Clipper();

            // From the perspective of Clipper lines are polygons too
            // Closed paths == polygons
            // Open paths == lines
            var polygonGroups = from y in Enumerable.Range(0, tmxLayer.Height)
                                from x in Enumerable.Range(0, tmxLayer.Width)
                                let rawTileId = tmxLayer.GetRawTileIdAt(x, y)
                                let tileId = TmxMath.GetTileIdWithoutFlags(rawTileId)
                                where tileId != 0
                                let tile = tmxMap.Tiles[tileId]
                                from polygon in tile.ObjectGroup.Objects
                                where (polygon as TmxHasPoints) != null
                                let groupX = x / LayerClipper.GroupBySize
                                let groupY = y / LayerClipper.GroupBySize
                                group new
                                {
                                    PositionOnMap = tmxMap.GetMapPositionAt(x, y, tile),
                                    HasPointsInterface = polygon as TmxHasPoints,
                                    TmxObjectInterface = polygon,
                                    IsFlippedDiagnoally = TmxMath.IsTileFlippedDiagonally(rawTileId),
                                    IsFlippedHorizontally = TmxMath.IsTileFlippedHorizontally(rawTileId),
                                    IsFlippedVertically = TmxMath.IsTileFlippedVertically(rawTileId),
                                    TileCenter = new PointF(tile.TileSize.Width * 0.5f, tile.TileSize.Height * 0.5f),
                                }
                                by Tuple.Create(groupX, groupY);

            int groupIndex = 0;
            int groupCount = polygonGroups.Count();

            foreach (var polyGroup in polygonGroups)
            {
                if (groupIndex % 5 == 0)
                {
                    progFunc(String.Format("Clipping '{0}' polygons: {1}%", tmxLayer.Name, (groupIndex / (float)groupCount) * 100));
                }
                groupIndex++;

                // The "groupClipper" clips the polygons in a smaller part of the world
                ClipperLib.Clipper groupClipper = new ClipperLib.Clipper();

                // Add all our polygons to the Clipper library so it can reduce all the polygons to a (hopefully small) number of paths
                foreach (var poly in polyGroup)
                {
                    // Create a clipper library polygon out of each and add it to our collection
                    ClipperPolygon clipperPolygon = new ClipperPolygon();

                    // Our points may be transformed due to tile flipping/rotation
                    // Before we transform them we put all the points into local space relative to the tile
                    SizeF offset = new SizeF(poly.TmxObjectInterface.Position);
                    PointF[] transformedPoints = poly.HasPointsInterface.Points.Select(pt => PointF.Add(pt, offset)).ToArray();

                    // Now transform the points relative to the tile
                    TmxMath.TransformPoints(transformedPoints, poly.TileCenter, poly.IsFlippedDiagnoally, poly.IsFlippedHorizontally, poly.IsFlippedVertically);

                    foreach (var pt in transformedPoints)
                    {
                        float x = poly.PositionOnMap.X + pt.X;
                        float y = poly.PositionOnMap.Y + pt.Y;

                        ClipperLib.IntPoint point = xfFunc(x, y);
                        clipperPolygon.Add(point);
                    }

                    // Because of Unity's cooridnate system, the winding order of the polygons must be reversed
                    clipperPolygon.Reverse();

                    // Add the "subject"
                    groupClipper.AddPath(clipperPolygon, ClipperLib.PolyType.ptSubject, poly.HasPointsInterface.ArePointsClosed());
                }

                // Get a solution for this group
                ClipperLib.PolyTree solution = new ClipperLib.PolyTree();
                groupClipper.Execute(ClipperLib.ClipType.ctUnion, solution, LayerClipper.SubjectFillRule, LayerClipper.ClipFillRule);

                // Combine the solutions into the full clipper
                fullClipper.AddPaths(ClipperLib.Clipper.ClosedPathsFromPolyTree(solution), ClipperLib.PolyType.ptSubject, true);
                fullClipper.AddPaths(ClipperLib.Clipper.OpenPathsFromPolyTree(solution), ClipperLib.PolyType.ptSubject, false);
            }
            progFunc(String.Format("Clipping '{0}' polygons: 100%", tmxLayer.Name));

            ClipperLib.PolyTree fullSolution = new ClipperLib.PolyTree();
            fullClipper.Execute(ClipperLib.ClipType.ctUnion, fullSolution, LayerClipper.SubjectFillRule, LayerClipper.ClipFillRule);

            return fullSolution;
        }
コード例 #35
0
        public static TmxLayer FromXml(XElement elem, TmxLayerNode parent, TmxMap tmxMap)
        {
            TmxLayer tmxLayer = new TmxLayer(parent, tmxMap);

            tmxLayer.FromXmlInternal(elem);

            // We can build a layer from a "tile layer" (default) or an "image layer"
            if (elem.Name == "layer")
            {
                tmxLayer.Width  = TmxHelper.GetAttributeAsInt(elem, "width");
                tmxLayer.Height = TmxHelper.GetAttributeAsInt(elem, "height");
                tmxLayer.ParseData(elem.Element("data"));
            }
            else if (elem.Name == "imagelayer")
            {
                XElement xmlImage = elem.Element("image");
                if (xmlImage == null)
                {
                    Logger.WriteWarning("Image Layer '{0}' is being ignored since it has no image.", tmxLayer.Name);
                    tmxLayer.Ignore = IgnoreSettings.True;
                    return(tmxLayer);
                }

                // An image layer is sort of like an tile layer but with just one tile
                tmxLayer.Width  = 1;
                tmxLayer.Height = 1;

                // Find the "tile" that matches our image
                string  imagePath = TmxHelper.GetAttributeAsFullPath(elem.Element("image"), "source");
                TmxTile tile      = tmxMap.Tiles.First(t => t.Value.TmxImage.AbsolutePath == imagePath).Value;
                tmxLayer.TileIds = new uint[1] {
                    tile.GlobalId
                };

                // The image layer needs to be tranlated in an interesting way when expressed as a tile layer
                PointF translated = tmxLayer.Offset;

                // Make up for height of a regular tile in the map
                translated.Y -= (float)tmxMap.TileHeight;

                // Make up for the height of this image
                translated.Y += (float)tile.TmxImage.Size.Height;

                // Correct for any orientation effects on the map (like isometric)
                // (We essentially undo the translation via orientation here)
                PointF orientation = TmxMath.TileCornerInScreenCoordinates(tmxMap, 0, 0);
                translated.X -= orientation.X;
                translated.Y -= orientation.Y;

                // Translate by the x and y coordiantes
                translated.X   += TmxHelper.GetAttributeAsFloat(elem, "x", 0);
                translated.Y   += TmxHelper.GetAttributeAsFloat(elem, "y", 0);
                tmxLayer.Offset = translated;
            }

            // Sometimes TMX files have "dead" tiles in them (tiles that were removed but are still referenced)
            // Remove these tiles from the layer by replacing them with zero
            for (int t = 0; t < tmxLayer.TileIds.Length; ++t)
            {
                uint tileId = tmxLayer.TileIds[t];
                tileId = TmxMath.GetTileIdWithoutFlags(tileId);
                if (!tmxMap.Tiles.ContainsKey(tileId))
                {
                    tmxLayer.TileIds[t] = 0;
                }
            }

            // Each layer will be broken down into "meshes" which are collections of tiles matching the same texture or animation
            tmxLayer.Meshes = TmxMesh.ListFromTmxLayer(tmxLayer);

            // Each layer may contain different collision types which are themselves put into "Collison Layers" to be processed later
            tmxLayer.BuildCollisionLayers();

            return(tmxLayer);
        }
コード例 #36
0
ファイル: LayerClipper.cs プロジェクト: mdhausman/Tiled2Unity
        public static ClipperLib.PolyTree ExecuteClipper(TmxMap tmxMap, TmxLayer tmxLayer, TransformPointFunc xfFunc, ProgressFunc progFunc)
        {
            // The "fullClipper" combines the clipper results from the smaller pieces
            ClipperLib.Clipper fullClipper = new ClipperLib.Clipper();

            // From the perspective of Clipper lines are polygons too
            // Closed paths == polygons
            // Open paths == lines
            var polygonGroups = from y in Enumerable.Range(0, tmxLayer.Height)
                                from x in Enumerable.Range(0, tmxLayer.Width)
                                let rawTileId = tmxLayer.GetRawTileIdAt(x, y)
                                                let tileId = TmxMath.GetTileIdWithoutFlags(rawTileId)
                                                             where tileId != 0
                                                             let tile = tmxMap.Tiles[tileId]
                                                                        from polygon in tile.ObjectGroup.Objects
                                                                        where (polygon as TmxHasPoints) != null
                                                                        let groupX = x / LayerClipper.GroupBySize
                                                                                     let groupY = y / LayerClipper.GroupBySize
                                                                                                  group new
            {
                PositionOnMap         = tmxMap.GetMapPositionAt(x, y, tile),
                HasPointsInterface    = polygon as TmxHasPoints,
                TmxObjectInterface    = polygon,
                IsFlippedDiagnoally   = TmxMath.IsTileFlippedDiagonally(rawTileId),
                IsFlippedHorizontally = TmxMath.IsTileFlippedHorizontally(rawTileId),
                IsFlippedVertically   = TmxMath.IsTileFlippedVertically(rawTileId),
                TileCenter            = new PointF(tile.TileSize.Width * 0.5f, tile.TileSize.Height * 0.5f),
            }
            by Tuple.Create(groupX, groupY);

            int groupIndex = 0;
            int groupCount = polygonGroups.Count();

            foreach (var polyGroup in polygonGroups)
            {
                if (groupIndex % 5 == 0)
                {
                    progFunc(String.Format("Clipping '{0}' polygons: {1}%", tmxLayer.Name, (groupIndex / (float)groupCount) * 100));
                }
                groupIndex++;

                // The "groupClipper" clips the polygons in a smaller part of the world
                ClipperLib.Clipper groupClipper = new ClipperLib.Clipper();

                // Add all our polygons to the Clipper library so it can reduce all the polygons to a (hopefully small) number of paths
                foreach (var poly in polyGroup)
                {
                    // Create a clipper library polygon out of each and add it to our collection
                    ClipperPolygon clipperPolygon = new ClipperPolygon();

                    // Our points may be transformed due to tile flipping/rotation
                    // Before we transform them we put all the points into local space relative to the tile
                    SizeF    offset            = new SizeF(poly.TmxObjectInterface.Position);
                    PointF[] transformedPoints = poly.HasPointsInterface.Points.Select(pt => PointF.Add(pt, offset)).ToArray();

                    // Now transform the points relative to the tile
                    TmxMath.TransformPoints(transformedPoints, poly.TileCenter, poly.IsFlippedDiagnoally, poly.IsFlippedHorizontally, poly.IsFlippedVertically);

                    foreach (var pt in transformedPoints)
                    {
                        float x = poly.PositionOnMap.X + pt.X;
                        float y = poly.PositionOnMap.Y + pt.Y;

                        ClipperLib.IntPoint point = xfFunc(x, y);
                        clipperPolygon.Add(point);
                    }

                    // Because of Unity's cooridnate system, the winding order of the polygons must be reversed
                    clipperPolygon.Reverse();

                    // Add the "subject"
                    groupClipper.AddPath(clipperPolygon, ClipperLib.PolyType.ptSubject, poly.HasPointsInterface.ArePointsClosed());
                }

                // Get a solution for this group
                ClipperLib.PolyTree solution = new ClipperLib.PolyTree();
                groupClipper.Execute(ClipperLib.ClipType.ctUnion, solution, LayerClipper.SubjectFillRule, LayerClipper.ClipFillRule);

                // Combine the solutions into the full clipper
                fullClipper.AddPaths(ClipperLib.Clipper.ClosedPathsFromPolyTree(solution), ClipperLib.PolyType.ptSubject, true);
                fullClipper.AddPaths(ClipperLib.Clipper.OpenPathsFromPolyTree(solution), ClipperLib.PolyType.ptSubject, false);
            }
            progFunc(String.Format("Clipping '{0}' polygons: 100%", tmxLayer.Name));

            ClipperLib.PolyTree fullSolution = new ClipperLib.PolyTree();
            fullClipper.Execute(ClipperLib.ClipType.ctUnion, fullSolution, LayerClipper.SubjectFillRule, LayerClipper.ClipFillRule);

            return(fullSolution);
        }
コード例 #37
0
 private int GetMaxTilesHigh(TmxLayer layer)
 {
     return(Math.Min(layer.Height, MaxPreviewTilesHigh));
 }
コード例 #38
0
        private XElement CreateCollisionElementForLayer(TmxLayer layer)
        {
            // Collision elements look like this
            // (Can also have EdgeCollider2Ds)
            //      <GameOject name="Collision">
            //        <PolygonCollider2D>
            //          <Path>list of points</Path>
            //          <Path>another list of points</Path>
            //        </PolygonCollider2D>
            //      </GameOject>

            LayerClipper.TransformPointFunc xfFunc =
                delegate(float x, float y)
            {
                // Transform point to Unity space
                PointF pointUnity3d       = PointFToUnityVector_NoScale(new PointF(x, y));
                ClipperLib.IntPoint point = new ClipperLib.IntPoint(pointUnity3d.X, pointUnity3d.Y);
                return(point);
            };

            LayerClipper.ProgressFunc progFunc =
                delegate(string prog)
            {
                Logger.WriteLine(prog);
            };

            ClipperLib.PolyTree solution = LayerClipper.ExecuteClipper(this.tmxMap, layer, xfFunc, progFunc);

            var paths = ClipperLib.Clipper.ClosedPathsFromPolyTree(solution);

            if (paths.Count >= MaxNumberOfSafePaths)
            {
                StringBuilder warning = new StringBuilder();
                warning.AppendFormat("Layer '{0}' has a large number of polygon paths ({1}).", layer.Name, paths.Count);
                warning.AppendLine("  Importing this layer may be slow in Unity. (Can take an hour or more for +1000 paths.)");
                warning.AppendLine("  Check polygon/rectangle objects in Tile Collision Editor in Tiled and use 'Snap to Grid' or 'Snap to Fine Grid'.");
                warning.AppendLine("  You want colliders to be set up so they can be merged with colliders on neighboring tiles, reducing path count considerably.");
                warning.AppendLine("  In some cases the size of the map may need to be reduced.");
                Logger.WriteWarning(warning.ToString());
            }

            // Add our polygon and edge colliders
            List <XElement> polyColliderElements = new List <XElement>();

            if (layer.IsExportingConvexPolygons())
            {
                AddPolygonCollider2DElements_Convex(solution, polyColliderElements);
            }
            else
            {
                AddPolygonCollider2DElements_Complex(solution, polyColliderElements);
            }

            AddEdgeCollider2DElements(ClipperLib.Clipper.OpenPathsFromPolyTree(solution), polyColliderElements);

            if (polyColliderElements.Count() == 0)
            {
                // No collisions on this layer
                return(null);
            }

            XElement gameObjectCollision =
                new XElement("GameObject",
                             new XAttribute("name", "Collision"),
                             polyColliderElements);

            // Collision layer may have a name and "unity physics layer" to go with it
            // (But not if we're using unity:layer override)
            if (String.IsNullOrEmpty(layer.UnityLayerOverrideName) && !String.IsNullOrEmpty(layer.Name))
            {
                gameObjectCollision.SetAttributeValue("name", "Collision_" + layer.Name);
                gameObjectCollision.SetAttributeValue("layer", layer.Name);
            }

            return(gameObjectCollision);
        }
コード例 #39
0
ファイル: TmxLayer.Xml.cs プロジェクト: knunery/Tiled2Unity
        public static TmxLayer FromXml(XElement elem, TmxMap tmxMap)
        {
            Program.WriteVerbose(elem.ToString());
            TmxLayer tmxLayer = new TmxLayer(tmxMap);

            // Order within Xml file is import for layer types
            tmxLayer.XmlElementIndex = elem.NodesBeforeSelf().Count();

            // Have to decorate layer names in order to force them into being unique
            // Also, can't have whitespace in the name because Unity will add underscores
            tmxLayer.Name = TmxHelper.GetAttributeAsString(elem, "name");

            tmxLayer.Visible = TmxHelper.GetAttributeAsInt(elem, "visible", 1) == 1;
            tmxLayer.Opacity = TmxHelper.GetAttributeAsFloat(elem, "opacity", 1);

            PointF offset = new PointF(0, 0);
            offset.X = TmxHelper.GetAttributeAsFloat(elem, "offsetx", 0);
            offset.Y = TmxHelper.GetAttributeAsFloat(elem, "offsety", 0);
            tmxLayer.Offset = offset;

            // Set our properties
            tmxLayer.Properties = TmxProperties.FromXml(elem);

            // Set the "ignore" setting on this layer
            tmxLayer.Ignore = tmxLayer.Properties.GetPropertyValueAsEnum<IgnoreSettings>("unity:ignore", IgnoreSettings.False);

            // We can build a layer from a "tile layer" (default) or an "image layer"
            if (elem.Name == "layer")
            {
                tmxLayer.Width = TmxHelper.GetAttributeAsInt(elem, "width");
                tmxLayer.Height = TmxHelper.GetAttributeAsInt(elem, "height");
                tmxLayer.ParseData(elem.Element("data"));
            }
            else if (elem.Name == "imagelayer")
            {
                XElement xmlImage = elem.Element("image");
                if (xmlImage == null)
                {
                    Program.WriteWarning("Image Layer '{0}' is being ignored since it has no image.", tmxLayer.Name);
                    tmxLayer.Ignore = IgnoreSettings.True;
                    return tmxLayer;
                }

                // An image layer is sort of like an tile layer but with just one tile
                tmxLayer.Width = 1;
                tmxLayer.Height = 1;

                // Find the "tile" that matches our image
                string imagePath = TmxHelper.GetAttributeAsFullPath(elem.Element("image"), "source");
                TmxTile tile = tmxMap.Tiles.First(t => t.Value.TmxImage.AbsolutePath == imagePath).Value;
                tmxLayer.TileIds = new uint[1] { tile.GlobalId };

                // The image layer needs to be tranlated in an interesting way when expressed as a tile layer
                PointF translated = tmxLayer.Offset;

                // Make up for height of a regular tile in the map
                translated.Y -= (float)tmxMap.TileHeight;

                // Make up for the height of this image
                translated.Y += (float)tile.TmxImage.Size.Height;

                // Correct for any orientation effects on the map (like isometric)
                // (We essentially undo the translation via orientation here)
                PointF orientation = TmxMath.TileCornerInScreenCoordinates(tmxMap, 0, 0);
                translated.X -= orientation.X;
                translated.Y -= orientation.Y;

                // Translate by the x and y coordiantes
                translated.X += TmxHelper.GetAttributeAsFloat(elem, "x", 0);
                translated.Y += TmxHelper.GetAttributeAsFloat(elem, "y", 0);
                tmxLayer.Offset = translated;
            }

            // Each layer will be broken down into "meshes" which are collections of tiles matching the same texture or animation
            tmxLayer.Meshes = TmxMesh.ListFromTmxLayer(tmxLayer);

            return tmxLayer;
        }
コード例 #40
0
        public static TmxLayer FromXml(XElement elem, TmxMap tmxMap)
        {
            Program.WriteVerbose(elem.ToString());
            TmxLayer tmxLayer = new TmxLayer(tmxMap);

            // Order within Xml file is import for layer types
            tmxLayer.XmlElementIndex = elem.NodesBeforeSelf().Count();

            // Have to decorate layer names in order to force them into being unique
            // Also, can't have whitespace in the name because Unity will add underscores
            tmxLayer.Name = TmxHelper.GetAttributeAsString(elem, "name");

            tmxLayer.Visible = TmxHelper.GetAttributeAsInt(elem, "visible", 1) == 1;
            tmxLayer.Opacity = TmxHelper.GetAttributeAsFloat(elem, "opacity", 1);

            PointF offset = new PointF(0, 0);

            offset.X        = TmxHelper.GetAttributeAsFloat(elem, "offsetx", 0);
            offset.Y        = TmxHelper.GetAttributeAsFloat(elem, "offsety", 0);
            tmxLayer.Offset = offset;

            // Set our properties
            tmxLayer.Properties = TmxProperties.FromXml(elem);

            // Set the "ignore" setting on this layer
            tmxLayer.Ignore = tmxLayer.Properties.GetPropertyValueAsEnum <IgnoreSettings>("unity:ignore", IgnoreSettings.False);

            // We can build a layer from a "tile layer" (default) or an "image layer"
            if (elem.Name == "layer")
            {
                tmxLayer.Width  = TmxHelper.GetAttributeAsInt(elem, "width");
                tmxLayer.Height = TmxHelper.GetAttributeAsInt(elem, "height");
                tmxLayer.ParseData(elem.Element("data"));
            }
            else if (elem.Name == "imagelayer")
            {
                XElement xmlImage = elem.Element("image");
                if (xmlImage == null)
                {
                    Program.WriteWarning("Image Layer '{0}' is being ignored since it has no image.", tmxLayer.Name);
                    tmxLayer.Ignore = IgnoreSettings.True;
                    return(tmxLayer);
                }

                // An image layer is sort of like an tile layer but with just one tile
                tmxLayer.Width  = 1;
                tmxLayer.Height = 1;

                // Find the "tile" that matches our image
                string  imagePath = TmxHelper.GetAttributeAsFullPath(elem.Element("image"), "source");
                TmxTile tile      = tmxMap.Tiles.First(t => t.Value.TmxImage.AbsolutePath == imagePath).Value;
                tmxLayer.TileIds = new uint[1] {
                    tile.GlobalId
                };

                // The image layer needs to be tranlated in an interesting way when expressed as a tile layer
                PointF translated = tmxLayer.Offset;

                // Make up for height of a regular tile in the map
                translated.Y -= (float)tmxMap.TileHeight;

                // Make up for the height of this image
                translated.Y += (float)tile.TmxImage.Size.Height;

                // Correct for any orientation effects on the map (like isometric)
                // (We essentially undo the translation via orientation here)
                PointF orientation = TmxMath.TileCornerInScreenCoordinates(tmxMap, 0, 0);
                translated.X -= orientation.X;
                translated.Y -= orientation.Y;

                // Translate by the x and y coordiantes
                translated.X   += TmxHelper.GetAttributeAsFloat(elem, "x", 0);
                translated.Y   += TmxHelper.GetAttributeAsFloat(elem, "y", 0);
                tmxLayer.Offset = translated;
            }

            // Each layer will be broken down into "meshes" which are collections of tiles matching the same texture or animation
            tmxLayer.Meshes = TmxMesh.ListFromTmxLayer(tmxLayer);

            return(tmxLayer);
        }
コード例 #41
0
        private void DrawLayerColliders(Graphics g, TmxLayer layer, Color polyColor, Color lineColor)
        {
            LayerClipper.TransformPointFunc xfFunc = (x,y) => new ClipperLib.IntPoint(x, y);
            LayerClipper.ProgressFunc progFunc = (prog) => { }; // do nothing

            ClipperLib.PolyTree solution = LayerClipper.ExecuteClipper(this.tmxMap, layer, xfFunc, progFunc);

            using (GraphicsPath path = new GraphicsPath())
            using (Pen pen = new Pen(lineColor, 1.0f))
            using (Brush brush = new HatchBrush(HatchStyle.ForwardDiagonal, lineColor, polyColor))
            {
                pen.Alignment = PenAlignment.Inset;

                // Draw all closed polygons
                foreach (var points in ClipperLib.Clipper.ClosedPathsFromPolyTree(solution))
                {
                    var pointfs = points.Select(pt => new PointF(pt.X, pt.Y));
                    path.AddPolygon(pointfs.ToArray());
                }
                if (path.PointCount > 0)
                {
                    g.FillPath(brush, path);
                    g.DrawPath(pen, path);
                }

                // Draw all lines (open polygons)
                path.Reset();
                foreach (var points in ClipperLib.Clipper.OpenPathsFromPolyTree(solution))
                {
                    var pointfs = points.Select(pt => new PointF(pt.X, pt.Y));
                    path.StartFigure();
                    path.AddLines(pointfs.ToArray());
                }
                if (path.PointCount > 0)
                {
                    g.DrawPath(pen, path);
                }
            }
        }
コード例 #42
0
        private XElement CreateCollisionElementForLayer(TmxLayer layer)
        {
            // Collision elements look like this
            // (Can also have EdgeCollider2Ds)
            //      <GameOject name="Collision">
            //        <PolygonCollider2D>
            //          <Path>list of points</Path>
            //          <Path>another list of points</Path>
            //        </PolygonCollider2D>
            //      </GameOject>

            LayerClipper.TransformPointFunc xfFunc =
                delegate(float x, float y)
                {
                    // Transform point to Unity space
                    PointF pointUnity3d = PointFToUnityVector_NoScale(new PointF(x, y));
                    ClipperLib.IntPoint point = new ClipperLib.IntPoint(pointUnity3d.X, pointUnity3d.Y);
                    return point;
                };

            LayerClipper.ProgressFunc progFunc =
                delegate(string prog)
                {
                    Program.WriteLine(prog);
                };

            ClipperLib.PolyTree solution = LayerClipper.ExecuteClipper(this.tmxMap, layer, xfFunc, progFunc);

            var paths = ClipperLib.Clipper.ClosedPathsFromPolyTree(solution);
            if (paths.Count >= MaxNumberOfSafePaths)
            {
                StringBuilder warning = new StringBuilder();
                warning.AppendFormat("Layer '{0}' has a large number of polygon paths ({1}).", layer.Name, paths.Count);
                warning.AppendLine("  Importing this layer may be slow in Unity. (Can take an hour or more for +1000 paths.)");
                warning.AppendLine("  Check polygon/rectangle objects in Tile Collision Editor in Tiled and use 'Snap to Grid' or 'Snap to Fine Grid'.");
                warning.AppendLine("  You want colliders to be set up so they can be merged with colliders on neighboring tiles, reducing path count considerably.");
                warning.AppendLine("  In some cases the size of the map may need to be reduced.");
                Program.WriteWarning(warning.ToString());
            }

            // Add our polygon and edge colliders
            List<XElement> polyColliderElements = new List<XElement>();

            if (layer.IsExportingConvexPolygons())
            {
                AddPolygonCollider2DElements_Convex(solution, polyColliderElements);
            }
            else
            {
                AddPolygonCollider2DElements_Complex(solution, polyColliderElements);
            }

            AddEdgeCollider2DElements(ClipperLib.Clipper.OpenPathsFromPolyTree(solution), polyColliderElements);

            if (polyColliderElements.Count() == 0)
            {
                // No collisions on this layer
                return null;
            }

            XElement gameObjectCollision =
                new XElement("GameObject",
                    new XAttribute("name", "Collision"),
                    polyColliderElements);

            // Collision layer may have a name and "unity physics layer" to go with it
            // (But not if we're using unity:layer override)
            if (String.IsNullOrEmpty(layer.UnityLayerOverrideName) && !String.IsNullOrEmpty(layer.Name))
            {
                gameObjectCollision.SetAttributeValue("name", "Collision_" + layer.Name);
                gameObjectCollision.SetAttributeValue("layer", layer.Name);
            }

            return gameObjectCollision;
        }