Exemple #1
0
 private void ReadTileIds(XElement xml)
 {
     TileIds.Clear();
     if (ParentData.Encoding == DataEncoding.Xml)
     {
         ReadTileIds_Xml(xml);
     }
     else if (ParentData.Encoding == DataEncoding.Csv)
     {
         ReadTiledIds_Csv(xml.Value);
     }
     else if (ParentData.Encoding == DataEncoding.Base64)
     {
         ReadTileIds_Base64(xml.Value);
     }
     else
     {
         TmxException.ThrowFormat("Unsupported encoding for chunk data in layer '{0}'", ParentData.ParentLayer);
     }
     for (int i = 0; i < TileIds.Count; i++)
     {
         uint tileId = TileIds[i];
         tileId = TmxMath.GetTileIdWithoutFlags(tileId);
         if (!ParentData.ParentLayer.ParentMap.Tiles.ContainsKey(tileId))
         {
             TileIds[i] = 0u;
         }
     }
 }
Exemple #2
0
        protected override void InternalFromXml(System.Xml.Linq.XElement xml, TmxMap tmxMap)
        {
            // Get the tile
            uint gid = TmxHelper.GetAttributeAsUInt(xml, "gid");

            this.FlippedHorizontal = TmxMath.IsTileFlippedHorizontally(gid);
            this.FlippedVertical   = TmxMath.IsTileFlippedVertically(gid);
            uint rawTileId = TmxMath.GetTileIdWithoutFlags(gid);

            this.Tile = tmxMap.Tiles[rawTileId];

            // The tile needs to have a mesh on it.
            // Note: The tile may already be referenced by another TmxObjectTile instance, and as such will have its mesh data already made
            if (this.Tile.Meshes.Count() == 0)
            {
                this.Tile.Meshes = TmxMesh.FromTmxTile(this.Tile, tmxMap);
            }

            // Check properties for layer placement
            if (this.Properties.PropertyMap.ContainsKey("unity:sortingLayerName"))
            {
                this.SortingLayerName = this.Properties.GetPropertyValueAsString("unity:sortingLayerName");
            }
            if (this.Properties.PropertyMap.ContainsKey("unity:sortingOrder"))
            {
                this.SortingOrder = this.Properties.GetPropertyValueAsInt("unity:sortingOrder");
            }
        }
Exemple #3
0
 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;
                     }
                 }
             }
         }
     }
 }
Exemple #4
0
        public static TmxObject FromXml(XElement xml, TmxObjectGroup tmxObjectGroup, TmxMap tmxMap)
        {
            Logger.WriteVerbose("Parsing object ...");
            uint attributeAsUInt = TmxHelper.GetAttributeAsUInt(xml, "tid", 0u);

            if (attributeAsUInt != 0 && tmxMap.Templates.TryGetValue(attributeAsUInt, out TgxTemplate value))
            {
                xml    = value.Templatize(xml);
                tmxMap = value.TemplateGroupMap;
            }
            TmxObject tmxObject = null;

            if (xml.Element("ellipse") != null)
            {
                tmxObject = new TmxObjectEllipse();
            }
            else if (xml.Element("polygon") != null)
            {
                tmxObject = new TmxObjectPolygon();
            }
            else if (xml.Element("polyline") != null)
            {
                tmxObject = new TmxObjectPolyline();
            }
            else if (xml.Attribute("gid") != null)
            {
                uint attributeAsUInt2 = TmxHelper.GetAttributeAsUInt(xml, "gid");
                attributeAsUInt2 = TmxMath.GetTileIdWithoutFlags(attributeAsUInt2);
                if (tmxMap.Tiles.ContainsKey(attributeAsUInt2))
                {
                    tmxObject = new TmxObjectTile();
                }
                else
                {
                    Logger.WriteWarning("Tile Id {0} not found in tilesets. Using a rectangle instead.\n{1}", attributeAsUInt2, xml.ToString());
                    tmxObject = new TmxObjectRectangle();
                }
            }
            else
            {
                tmxObject = new TmxObjectRectangle();
            }
            tmxObject.Id                = TmxHelper.GetAttributeAsInt(xml, "id", 0);
            tmxObject.Name              = TmxHelper.GetAttributeAsString(xml, "name", "");
            tmxObject.Type              = TmxHelper.GetAttributeAsString(xml, "type", "");
            tmxObject.Visible           = (TmxHelper.GetAttributeAsInt(xml, "visible", 1) == 1);
            tmxObject.ParentObjectGroup = tmxObjectGroup;
            float attributeAsFloat  = TmxHelper.GetAttributeAsFloat(xml, "x");
            float attributeAsFloat2 = TmxHelper.GetAttributeAsFloat(xml, "y");
            float attributeAsFloat3 = TmxHelper.GetAttributeAsFloat(xml, "width", 0f);
            float attributeAsFloat4 = TmxHelper.GetAttributeAsFloat(xml, "height", 0f);
            float attributeAsFloat5 = TmxHelper.GetAttributeAsFloat(xml, "rotation", 0f);

            tmxObject.Position   = new PointF(attributeAsFloat, attributeAsFloat2);
            tmxObject.Size       = new SizeF(attributeAsFloat3, attributeAsFloat4);
            tmxObject.Rotation   = attributeAsFloat5;
            tmxObject.Properties = TmxProperties.FromXml(xml);
            tmxObject.InternalFromXml(xml, tmxMap);
            return(tmxObject);
        }
Exemple #5
0
 public TmxTile GetTileFromTileId(uint tileId)
 {
     if (tileId == 0)
     {
         return(null);
     }
     tileId = TmxMath.GetTileIdWithoutFlags(tileId);
     return(Tiles[tileId]);
 }
        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));
        }
Exemple #7
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;
                }
            }
        }
Exemple #8
0
        protected override void InternalFromXml(System.Xml.Linq.XElement xml, TmxMap tmxMap)
        {
            // Get the tile
            uint gid = TmxHelper.GetAttributeAsUInt(xml, "gid");

            this.FlippedHorizontal = TmxMath.IsTileFlippedHorizontally(gid);
            this.FlippedVertical   = TmxMath.IsTileFlippedVertically(gid);
            uint rawTileId = TmxMath.GetTileIdWithoutFlags(gid);

            this.Tile = tmxMap.Tiles[rawTileId];

            // The tile needs to have a mesh on it.
            // Note: The tile may already be referenced by another TmxObjectTile instance, and as such will have its mesh data already made
            if (this.Tile.Meshes.Count() == 0)
            {
                this.Tile.Meshes = TmxMesh.FromTmxTile(this.Tile, tmxMap);
            }
        }
        protected override void InternalFromXml(XElement xml, TmxMap tmxMap)
        {
            uint attributeAsUInt = TmxHelper.GetAttributeAsUInt(xml, "gid");

            FlippedHorizontal = TmxMath.IsTileFlippedHorizontally(attributeAsUInt);
            FlippedVertical   = TmxMath.IsTileFlippedVertically(attributeAsUInt);
            uint tileIdWithoutFlags = TmxMath.GetTileIdWithoutFlags(attributeAsUInt);

            Tile = tmxMap.Tiles[tileIdWithoutFlags];
            if (Tile.Meshes.Count() == 0)
            {
                Tile.Meshes = TmxMesh.FromTmxTile(Tile, tmxMap);
            }
            ExplicitSortingLayerName = base.Properties.GetPropertyValueAsString("unity:sortingLayerName", "");
            if (base.Properties.PropertyMap.ContainsKey("unity:sortingOrder"))
            {
                ExplicitSortingOrder = base.Properties.GetPropertyValueAsInt("unity:sortingOrder");
            }
        }
Exemple #10
0
        // Creates a TmxMesh from a tile (for tile objects)
        public static List <TmxMesh> FromTmxTile(TmxTile tmxTile, TmxMap tmxMap)
        {
            List <TmxMesh> meshes = new List <TmxMesh>();

            int timeMs = 0;

            foreach (var frame in tmxTile.Animation.Frames)
            {
                uint    frameTileId = frame.GlobalTileId;
                TmxTile frameTile   = tmxMap.Tiles[frameTileId];

                TmxMesh mesh = new TmxMesh();
                mesh.TileIds    = new uint[1];
                mesh.TileIds[0] = frameTileId;

                mesh.UniqueMeshName = String.Format("mesh_tile_{0}", TmxMath.GetTileIdWithoutFlags(frameTileId).ToString("D4"));
                mesh.TmxImage       = frameTile.TmxImage;
                mesh.ObjectName     = "tile_obj";

                // 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 = tmxTile.Animation.TotalTimeMs;

                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);
                }

                // Advance time
                timeMs += frame.DurationMs;

                // Add the animation frame to our list of meshes
                meshes.Add(mesh);
            }

            return(meshes);
        }
Exemple #11
0
        // Creates the text for a Wavefront OBJ file for the TmxMap
        private StringWriter BuildObjString()
        {
            IGenericDatabase <Vertex3> vertexDatabase = new HashIndexOf <Vertex3>();
            HashIndexOf <PointF>       uvDatabase     = new HashIndexOf <PointF>();

            // Are we allowing vertices to be written too (advanced option)
            if (Tiled2Unity.Settings.WriteableVertices)
            {
                // Replace vertex database with class that ensure each vertex (even ones with similar values) are unique
                Logger.WriteLine("Using writeable-vertices. This will increase the size of the mesh but will allow you mutate vertices through scripting. This is an advanced feature.");
                vertexDatabase = new GenericListDatabase <Vertex3>();
            }

            float mapLogicalHeight = this.tmxMap.MapSizeInPixels().Height;

            // Go through every face of every mesh of every visible layer and collect vertex and texture coordinate indices as you go
            int           groupCount  = 0;
            StringBuilder faceBuilder = new StringBuilder();

            foreach (var layer in this.tmxMap.Layers)
            {
                if (layer.Visible != true)
                {
                    continue;
                }

                if (layer.Ignore == TmxLayer.IgnoreSettings.Visual)
                {
                    continue;
                }

                // We're going to use this layer
                ++groupCount;

                // Enumerate over the tiles in the direction given by the draw order of the map
                var verticalRange   = (this.tmxMap.DrawOrderVertical == 1) ? Enumerable.Range(0, layer.Height) : Enumerable.Range(0, layer.Height).Reverse();
                var horizontalRange = (this.tmxMap.DrawOrderHorizontal == 1) ? Enumerable.Range(0, layer.Width) : Enumerable.Range(0, layer.Width).Reverse();

                foreach (TmxMesh mesh in layer.Meshes)
                {
                    Logger.WriteLine("Writing '{0}' mesh group", mesh.UniqueMeshName);
                    faceBuilder.AppendFormat("\ng {0}\n", mesh.UniqueMeshName);

                    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);
                            var vertices = CalculateFaceVertices(position, tile.TileSize, this.tmxMap.TileHeight, tile.Offset);

                            // 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, mapLogicalHeight);
                            }

                            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);
                            faceBuilder.AppendFormat("f {0} {1} {2} {3}\n", v0, v1, v2, v3);
                        }
                    }
                }
            }

            // Now go through any tile objects we may have and write them out as face groups as well
            foreach (var tmxMesh in this.tmxMap.GetUniqueListOfVisibleObjectTileMeshes())
            {
                // We're going to use this tile object
                groupCount++;

                Logger.WriteLine("Writing '{0}' tile group", tmxMesh.UniqueMeshName);
                faceBuilder.AppendFormat("\ng {0}\n", tmxMesh.UniqueMeshName);

                // Get the single tile associated with this mesh
                TmxTile tmxTile = this.tmxMap.Tiles[tmxMesh.TileIds[0]];

                var vertices = CalculateFaceVertices_TileObject(tmxTile.TileSize, tmxTile.Offset);
                var uvs      = CalculateFaceTextureCoordinates(tmxTile, false, false, false);

                // TileObjects have zero depth on their vertices. Their GameObject parent will set depth.
                FaceVertices faceVertices = new FaceVertices {
                    Vertices = vertices, Depth_z = 0.0f
                };

                // 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);
                faceBuilder.AppendFormat("f {0} {1} {2} {3}\n", v0, v1, v2, v3);
            }

            // All of our faces have been built and vertex and uv databases have been filled.
            // Start building out the obj file
            StringWriter objWriter = new StringWriter();

            objWriter.WriteLine("# Wavefront OBJ file automatically generated by Tiled2Unity");
            objWriter.WriteLine();

            Logger.WriteLine("Writing face vertices");
            objWriter.WriteLine("# Vertices (Count = {0})", vertexDatabase.List.Count());
            foreach (var v in vertexDatabase.List)
            {
                objWriter.WriteLine("v {0} {1} {2}", v.X, v.Y, v.Z);
            }
            objWriter.WriteLine();

            Logger.WriteLine("Writing face uv coordinates");
            objWriter.WriteLine("# Texture cooridinates (Count = {0})", uvDatabase.List.Count());
            foreach (var uv in uvDatabase.List)
            {
                objWriter.WriteLine("vt {0} {1}", uv.X, uv.Y);
            }
            objWriter.WriteLine();

            // Write the one indexed normal
            objWriter.WriteLine("# Normal");
            objWriter.WriteLine("vn 0 0 -1");
            objWriter.WriteLine();

            // Now we can copy over the string used to build the databases
            objWriter.WriteLine("# Groups (Count = {0})", groupCount);
            objWriter.WriteLine(faceBuilder.ToString());

            return(objWriter);
        }
Exemple #12
0
 public uint GetTileIdAt(int x, int y)
 {
     return(TmxMath.GetTileIdWithoutFlags(GetRawTileIdAt(x, y)));
 }
Exemple #13
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);
        }
Exemple #14
0
        // Creates the text for a Wavefront OBJ file for the TmxMap
        private StringWriter BuildObjString()
        {
            HashIndexOf <PointF> vertexDatabase = new HashIndexOf <PointF>();
            HashIndexOf <PointF> uvDatabase     = new HashIndexOf <PointF>();

            // Go through every face of every mesh of every visible layer and collect vertex and texture coordinate indices as you go
            int           groupCount  = 0;
            StringBuilder faceBuilder = new StringBuilder();

            foreach (var layer in this.tmxMap.Layers)
            {
                if (layer.Visible != true)
                {
                    continue;
                }

                if (layer.Ignore == TmxLayer.IgnoreSettings.Visual)
                {
                    continue;
                }

                // We're going to use this layer
                ++groupCount;

                // Enumerate over the tiles in the direction given by the draw order of the map
                var verticalRange   = (this.tmxMap.DrawOrderVertical == 1) ? Enumerable.Range(0, layer.Height) : Enumerable.Range(0, layer.Height).Reverse();
                var horizontalRange = (this.tmxMap.DrawOrderHorizontal == 1) ? Enumerable.Range(0, layer.Width) : Enumerable.Range(0, layer.Width).Reverse();

                foreach (TmxMesh mesh in layer.Meshes)
                {
                    Program.WriteLine("Writing '{0}' mesh group", mesh.UniqueMeshName);
                    faceBuilder.AppendFormat("\ng {0}\n", mesh.UniqueMeshName);

                    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);
                            var vertices = CalculateFaceVertices(position, tile.TileSize, this.tmxMap.TileHeight, tile.Offset);

                            // 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.Add(vertices[0]) + 1, uvDatabase.Add(uvs[0]) + 1);
                            string v1 = String.Format("{0}/{1}/1", vertexDatabase.Add(vertices[1]) + 1, uvDatabase.Add(uvs[1]) + 1);
                            string v2 = String.Format("{0}/{1}/1", vertexDatabase.Add(vertices[2]) + 1, uvDatabase.Add(uvs[2]) + 1);
                            string v3 = String.Format("{0}/{1}/1", vertexDatabase.Add(vertices[3]) + 1, uvDatabase.Add(uvs[3]) + 1);
                            faceBuilder.AppendFormat("f {0} {1} {2} {3}\n", v0, v1, v2, v3);
                        }
                    }
                }
            }

            // Now go through any tile objects we may have and write them out as face groups as well
            foreach (var tmxMesh in this.tmxMap.GetUniqueListOfVisibleObjectTileMeshes())
            {
                // We're going to use this tile object
                groupCount++;

                Program.WriteLine("Writing '{0}' tile group", tmxMesh.UniqueMeshName);
                faceBuilder.AppendFormat("\ng {0}\n", tmxMesh.UniqueMeshName);

                // Get the single tile associated with this mesh
                TmxTile tmxTile = this.tmxMap.Tiles[tmxMesh.TileIds[0]];

                var vertices = CalculateFaceVertices_TileObject(tmxTile.TileSize, tmxTile.Offset);
                var uvs      = CalculateFaceTextureCoordinates(tmxTile, false, false, false);

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

            // All of our faces have been built and vertex and uv databases have been filled.
            // Start building out the obj file
            StringWriter objWriter = new StringWriter();

            objWriter.WriteLine("# Wavefront OBJ file automatically generated by Tiled2Unity");
            objWriter.WriteLine();

            Program.WriteLine("Writing face vertices");
            objWriter.WriteLine("# Vertices (Count = {0})", vertexDatabase.List.Count());
            foreach (var v in vertexDatabase.List)
            {
                objWriter.WriteLine("v {0} {1} 0", v.X, v.Y);
            }
            objWriter.WriteLine();

            Program.WriteLine("Writing face uv coordinates");
            objWriter.WriteLine("# Texture cooridinates (Count = {0})", uvDatabase.List.Count());
            foreach (var uv in uvDatabase.List)
            {
                objWriter.WriteLine("vt {0} {1}", uv.X, uv.Y);
            }
            objWriter.WriteLine();

            // Write the one indexed normal
            objWriter.WriteLine("# Normal");
            objWriter.WriteLine("vn 0 0 -1");
            objWriter.WriteLine();

            // Now we can copy over the string used to build the databases
            objWriter.WriteLine("# Groups (Count = {0})", groupCount);
            objWriter.WriteLine(faceBuilder.ToString());

            return(objWriter);
        }
Exemple #15
0
        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);
        }
        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();

            // Limit to polygon "type" that matches the collision layer name (unless we are overriding the whole layer to a specific Unity Layer Name)
            bool usingUnityLayerOverride = !String.IsNullOrEmpty(tmxLayer.UnityLayerOverrideName);

            // From the perspective of Clipper lines are polygons too
            // Closed paths == polygons
            // Open paths == lines
            Dictionary <TupleInt2, List <PolygonGroup> > polygonGroups = new Dictionary <TupleInt2, List <PolygonGroup> >();

            foreach (int y in Enumerable.Range(0, tmxLayer.Height))
            {
                foreach (int x in Enumerable.Range(0, tmxLayer.Width))
                {
                    uint rawTileId = tmxLayer.GetRawTileIdAt(x, y);
                    if (rawTileId == 0)
                    {
                        continue;
                    }

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

                    foreach (TmxObject polygon in tile.ObjectGroup.Objects)
                    {
                        if (typeof(TmxHasPoints).IsAssignableFrom(polygon.GetType()) &&
                            (usingUnityLayerOverride || String.Compare(polygon.Type, tmxLayer.Name, true) == 0))
                        {
                            int groupX = x / LayerClipper.GroupBySize;
                            int groupY = y / LayerClipper.GroupBySize;

                            PolygonGroup poly = new PolygonGroup();
                            poly.PositionOnMap         = tmxMap.GetMapPositionAt(x, y, tile);
                            poly.HasPointsInterface    = polygon as TmxHasPoints;
                            poly.TmxObjectInterface    = polygon;
                            poly.IsFlippedDiagnoally   = TmxMath.IsTileFlippedDiagonally(rawTileId);
                            poly.IsFlippedHorizontally = TmxMath.IsTileFlippedHorizontally(rawTileId);
                            poly.IsFlippedVertically   = TmxMath.IsTileFlippedVertically(rawTileId);
                            poly.TileCenter            = new PointF(tile.TileSize.Width * 0.5f, tile.TileSize.Height * 0.5f);

                            TupleInt2 key = new TupleInt2(groupX, groupY);
                            if (!polygonGroups.ContainsKey(key))
                            {
                                polygonGroups[key] = new List <PolygonGroup>();
                            }
                            polygonGroups[key].Add(poly);
                        }
                    }
                }
            }
            // Tuple not supported in Mono 2.0 so doing this the old fashioned way, sorry
            //var polygonGroups = from y in Enumerable.Range(0, tmxLayer.Height)
            //                    from x in Enumerable.Range(0, tmxLayer.Width)
            //                    let rawTileId = tmxLayer.GetRawTileIdAt(x, y)
            //                    where rawTileId != 0
            //                    let tileId = TmxMath.GetTileIdWithoutFlags(rawTileId)
            //                    let tile = tmxMap.Tiles[tileId]
            //                    from polygon in tile.ObjectGroup.Objects
            //                    where (polygon as TmxHasPoints) != null
            //                    where  usingUnityLayerOverride || String.Compare(polygon.Type, tmxLayer.Name, true) == 0
            //                    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 (TupleInt2 key in polygonGroups.Keys)
            {
                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 (PolygonGroup poly in polygonGroups[key])
                {
                    // 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);
        }
Exemple #17
0
        public static TmxObject FromXml(XElement xml, TmxObjectGroup tmxObjectGroup, TmxMap tmxMap)
        {
            Logger.WriteLine("Parsing object ...");

            // What kind of TmxObject are we creating?
            TmxObject tmxObject = null;

            if (xml.Element("ellipse") != null)
            {
                tmxObject = new TmxObjectEllipse();
            }
            else if (xml.Element("polygon") != null)
            {
                tmxObject = new TmxObjectPolygon();
            }
            else if (xml.Element("polyline") != null)
            {
                tmxObject = new TmxObjectPolyline();
            }
            else if (xml.Attribute("gid") != null)
            {
                uint gid = TmxHelper.GetAttributeAsUInt(xml, "gid");
                gid = TmxMath.GetTileIdWithoutFlags(gid);
                if (tmxMap.Tiles.ContainsKey(gid))
                {
                    tmxObject = new TmxObjectTile();
                }
                else
                {
                    // For some reason, the tile is not in any of our tilesets
                    // Warn the user and use a rectangle
                    Logger.WriteWarning("Tile Id {0} not found in tilesets. Using a rectangle instead.\n{1}", gid, xml.ToString());
                    tmxObject = new TmxObjectRectangle();
                }
            }
            else
            {
                // Just a rectangle
                tmxObject = new TmxObjectRectangle();
            }

            // Data found on every object type
            tmxObject.Name              = TmxHelper.GetAttributeAsString(xml, "name", "");
            tmxObject.Type              = TmxHelper.GetAttributeAsString(xml, "type", "");
            tmxObject.Visible           = TmxHelper.GetAttributeAsInt(xml, "visible", 1) == 1;
            tmxObject.ParentObjectGroup = tmxObjectGroup;

            float x = TmxHelper.GetAttributeAsFloat(xml, "x");
            float y = TmxHelper.GetAttributeAsFloat(xml, "y");
            float w = TmxHelper.GetAttributeAsFloat(xml, "width", 0);
            float h = TmxHelper.GetAttributeAsFloat(xml, "height", 0);
            float r = TmxHelper.GetAttributeAsFloat(xml, "rotation", 0);

            tmxObject.Position = new System.Drawing.PointF(x, y);
            tmxObject.Size     = new System.Drawing.SizeF(w, h);
            tmxObject.Rotation = r;

            tmxObject.Properties = TmxProperties.FromXml(xml);

            tmxObject.InternalFromXml(xml, tmxMap);

            return(tmxObject);
        }
Exemple #18
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);
        }
Exemple #19
0
        private List <XElement> CreateImportFilesElements(string exportToUnityProjectPath)
        {
            List <XElement> elements = new List <XElement>();

            // Add the mesh file as raw text
            {
                StringWriter objBuilder = BuildObjString();

                XElement mesh =
                    new XElement("ImportMesh",
                                 new XAttribute("filename", this.tmxMap.Name + ".obj"),
                                 StringToBase64String(objBuilder.ToString()));

                elements.Add(mesh);
            }

            {
                // Add all image files as compressed base64 strings
                var layerImages = from layer in this.tmxMap.Layers
                                  where layer.Visible == true
                                  from rawTileId in layer.TileIds
                                  where rawTileId != 0
                                  let tileId                       = TmxMath.GetTileIdWithoutFlags(rawTileId)
                                                          let tile = this.tmxMap.Tiles[tileId]
                                                                     select tile.TmxImage;

                // Tile Objects may have images not yet references by a layer
                var objectImages = from objectGroup in this.tmxMap.ObjectGroups
                                   where objectGroup.Visible == true
                                   from tmxObject in objectGroup.Objects
                                   where tmxObject.Visible == true
                                   where tmxObject is TmxObjectTile
                                   let tmxTileObject = tmxObject as TmxObjectTile
                                                       from mesh in tmxTileObject.Tile.Meshes
                                                       select mesh.TmxImage;

                // Combine image paths from tile layers and object layers
                List <TmxImage> images = new List <TmxImage>();
                images.AddRange(layerImages);
                images.AddRange(objectImages);

                // Get rid of duplicate images
                TmxImageComparer imageComparer = new TmxImageComparer();
                images = images.Distinct(imageComparer).ToList();

                // Do not import files if they are already in the project (in the /Assets/ directory of where we're exporting too)
                string unityAssetsDir = Path.Combine(exportToUnityProjectPath, "Assets");

                foreach (TmxImage image in images)
                {
                    // If the copy from location comes from within the project we want to copy to, then don't do it.
                    // This allows us to have tileset images that are alreday in use by the Unity project
                    string saveToAssetsDir = unityAssetsDir.ToLower();
                    string copyFromDir     = image.AbsolutePath.ToLower();

                    if (copyFromDir.StartsWith(saveToAssetsDir))
                    {
                        XElement xmlInternalTexture = new XElement("InternalTexture");

                        // The path to the texture will be WRT to the Unity project root
                        string assetPath = image.AbsolutePath.Remove(0, exportToUnityProjectPath.Length);
                        assetPath = assetPath.TrimStart('\\');
                        assetPath = assetPath.TrimStart('/');
                        Program.WriteLine("InternalTexture : {0}", assetPath);

                        // Path to texture in the asset directory
                        xmlInternalTexture.SetAttributeValue("assetPath", assetPath);

                        // Transparent color key?
                        if (!String.IsNullOrEmpty(image.TransparentColor))
                        {
                            xmlInternalTexture.SetAttributeValue("alphaColorKey", image.TransparentColor);
                        }

                        // Are we using depth shaders on our materials?
                        if (Program.DepthBufferEnabled)
                        {
                            xmlInternalTexture.SetAttributeValue("usesDepthShaders", true);
                        }

                        elements.Add(xmlInternalTexture);
                    }
                    else
                    {
                        XElement xmlImportTexture = new XElement("ImportTexture");

                        // Note that compression is not available in Unity. Go with Base64 string. Blerg.
                        Program.WriteLine("ImportTexture : will import '{0}' to {1}", image.AbsolutePath, Path.Combine(unityAssetsDir, "Tiled2Unity\\Textures\\"));

                        // Is there a color key for transparency?
                        if (!String.IsNullOrEmpty(image.TransparentColor))
                        {
                            xmlImportTexture.SetAttributeValue("alphaColorKey", image.TransparentColor);
                        }

                        // Are we using depth shaders on our materials?
                        if (Program.DepthBufferEnabled)
                        {
                            xmlImportTexture.SetAttributeValue("usesDepthShaders", true);
                        }

                        // Bake the image file into the xml
                        xmlImportTexture.Add(new XAttribute("filename", Path.GetFileName(image.AbsolutePath)), FileToBase64String(image.AbsolutePath));

                        elements.Add(xmlImportTexture);
                    }
                }
            }

            return(elements);
        }
Exemple #20
0
        private List <XElement> CreateImportFilesElements(string exportToUnityProjectPath)
        {
            List <XElement> elements = new List <XElement>();

            // Add the mesh file as raw text
            {
                StringWriter objBuilder = BuildObjString();

                XElement mesh =
                    new XElement("ImportMesh",
                                 new XAttribute("filename", this.tmxMap.Name + ".obj"),
                                 StringToBase64String(objBuilder.ToString()));

                elements.Add(mesh);
            }

            {
                // Add all image files as compressed base64 strings
                var layerImages = from layer in this.tmxMap.Layers
                                  where layer.Visible == true
                                  from rawTileId in layer.TileIds
                                  where rawTileId != 0
                                  let tileId                       = TmxMath.GetTileIdWithoutFlags(rawTileId)
                                                          let tile = this.tmxMap.Tiles[tileId]
                                                                     select tile.TmxImage;

                // Find the images from the frames as well
                var frameImages = from layer in this.tmxMap.Layers
                                  where layer.Visible == true
                                  from rawTileId in layer.TileIds
                                  where rawTileId != 0
                                  let tileId                       = TmxMath.GetTileIdWithoutFlags(rawTileId)
                                                          let tile = this.tmxMap.Tiles[tileId]
                                                                     from rawFrame in tile.Animation.Frames
                                                                     let frameId                         = TmxMath.GetTileIdWithoutFlags(rawFrame.GlobalTileId)
                                                                                               let frame = this.tmxMap.Tiles[frameId]
                                                                                                           select frame.TmxImage;


                // Tile Objects may have images not yet references by a layer
                var objectImages = from objectGroup in this.tmxMap.ObjectGroups
                                   where objectGroup.Visible == true
                                   from tmxObject in objectGroup.Objects
                                   where tmxObject.Visible == true
                                   where tmxObject is TmxObjectTile
                                   let tmxTileObject = tmxObject as TmxObjectTile
                                                       from mesh in tmxTileObject.Tile.Meshes
                                                       select mesh.TmxImage;

                // Combine image paths from tile layers and object layers
                List <TmxImage> images = new List <TmxImage>();
                images.AddRange(layerImages);
                images.AddRange(frameImages);
                images.AddRange(objectImages);

                // Get rid of duplicate images
                TmxImageComparer imageComparer = new TmxImageComparer();
                images = images.Distinct(imageComparer).ToList();

                foreach (TmxImage image in images)
                {
                    // The source texture is internal if it has a sibling *.meta file
                    // We don't want to copy internal textures into Unity because they are already there.
                    bool isInternal = File.Exists(image.AbsolutePath + ".meta");
                    if (isInternal)
                    {
                        // The texture is already in the Unity project so don't import
                        XElement xmlInternalTexture = new XElement("InternalTexture");

                        // The path to the texture will be WRT to the Unity project root
                        string assetsFolder = GetUnityAssetsPath(image.AbsolutePath);
                        string assetPath    = image.AbsolutePath.Remove(0, assetsFolder.Length);
                        assetPath = "Assets" + assetPath;
                        assetPath = assetPath.Replace("\\", "/");

                        Logger.WriteLine("InternalTexture : {0}", assetPath);

                        // Path to texture in the asset directory
                        xmlInternalTexture.SetAttributeValue("assetPath", assetPath);

                        // Transparent color key?
                        if (!String.IsNullOrEmpty(image.TransparentColor))
                        {
                            xmlInternalTexture.SetAttributeValue("alphaColorKey", image.TransparentColor);
                        }

                        // Are we using depth shaders on our materials?
                        if (Tiled2Unity.Settings.DepthBufferEnabled)
                        {
                            xmlInternalTexture.SetAttributeValue("usesDepthShaders", true);
                        }

                        // Will the material be loaded as a resource?
                        if (this.tmxMap.IsResource)
                        {
                            xmlInternalTexture.SetAttributeValue("isResource", true);
                        }

                        elements.Add(xmlInternalTexture);
                    }
                    else
                    {
                        // The texture needs to be imported into the Unity project (under Tiled2Unity's care)
                        XElement xmlImportTexture = new XElement("ImportTexture");

                        // Note that compression is not available in Unity. Go with Base64 string. Blerg.
                        Logger.WriteLine("ImportTexture : will import '{0}' to {1}", image.AbsolutePath, Path.Combine(exportToUnityProjectPath, "Textures"));

                        // Is there a color key for transparency?
                        if (!String.IsNullOrEmpty(image.TransparentColor))
                        {
                            xmlImportTexture.SetAttributeValue("alphaColorKey", image.TransparentColor);
                        }

                        // Are we using depth shaders on our materials?
                        if (Tiled2Unity.Settings.DepthBufferEnabled)
                        {
                            xmlImportTexture.SetAttributeValue("usesDepthShaders", true);
                        }

                        // Will the material be loaded as a resource?
                        if (this.tmxMap.IsResource)
                        {
                            xmlImportTexture.SetAttributeValue("isResource", true);
                        }

                        // Bake the image file into the xml
                        xmlImportTexture.Add(new XAttribute("filename", Path.GetFileName(image.AbsolutePath)), FileToBase64String(image.AbsolutePath));

                        elements.Add(xmlImportTexture);
                    }
                }
            }

            return(elements);
        }
Exemple #21
0
        public static List <TmxMesh> FromTmxTile(TmxTile tmxTile, TmxMap tmxMap)
        {
            List <TmxMesh> list = new List <TmxMesh>();
            int            num  = 0;

            foreach (TmxFrame frame in tmxTile.Animation.Frames)
            {
                uint    globalTileId = frame.GlobalTileId;
                TmxTile tmxTile2     = tmxMap.Tiles[globalTileId];
                TmxMesh tmxMesh      = new TmxMesh();
                tmxMesh.TileIds                 = new uint[1];
                tmxMesh.TileIds[0]              = globalTileId;
                tmxMesh.UniqueMeshName          = string.Format("{0}_mesh_tile_{1}", tmxMap.Name, TmxMath.GetTileIdWithoutFlags(globalTileId).ToString("D4"));
                tmxMesh.TmxImage                = tmxTile2.TmxImage;
                tmxMesh.ObjectName              = "tile_obj";
                tmxMesh.StartTimeMs             = num;
                tmxMesh.DurationMs              = frame.DurationMs;
                tmxMesh.FullAnimationDurationMs = tmxTile.Animation.TotalTimeMs;
                if (tmxMesh.DurationMs != 0)
                {
                    TmxMesh tmxMesh2 = tmxMesh;
                    tmxMesh2.ObjectName += $"[{num}-{num + tmxMesh.DurationMs}][{tmxMesh.FullAnimationDurationMs}]";
                }
                num += frame.DurationMs;
                list.Add(tmxMesh);
            }
            return(list);
        }
Exemple #22
0
        public static PolyTree ExecuteClipper(TmxMap map, TmxChunk chunk, TransformPointFunc xfFunc)
        {
            ////for(int i=0;i<chunk.Height;i++)
            //// {
            ////     for(int j=0; j<chunk.Width;j++)
            ////     {
            ////         var raw = chunk.GetRawTileIdAt(j, i);
            ////      if(raw!=0)
            ////         {
            ////             var tid = TmxMath.GetTileIdWithoutFlags(raw);
            ////             var tile = map.Tiles[tid];
            ////             foreach(var p in tile.ObjectGroup.Objects)
            ////             {
            ////                 if(p is TmxHasPoints)
            ////                 {
            ////                     p.ToEnumerable().Where((x) =>
            ////                     {
            ////                         if (!usingUnityLayerOverride)
            ////                         {


            ////                             return string.Compare(tuple.Item1.Type, chunk.ParentData.ParentLayer.Name, true) == 0;
            ////                         }

            ////                         return true;
            ////                     });
            ////                 }

            ////             }
            ////         }
            ////     }
            //// }

            //     Clipper clipper = new Clipper(0);
            //     Tuple<TmxObject, TmxTile, uint> tuple = new Tuple<TmxObject, TmxTile, uint>(null, null, 0);
            //     bool usingUnityLayerOverride = !string.IsNullOrEmpty(chunk.ParentData.ParentLayer.UnityLayerOverrideName);
            //     foreach (var item2 in from h__TransparentIdentifier4 in (from y in Enumerable.Range(0, chunk.Height)
            //                                                              from x in Enumerable.Range(0, chunk.Width)
            //                                                              let rawTileId = chunk.GetRawTileIdAt(x, y)
            //                                                              where rawTileId != 0
            //                                                              let tileId = TmxMath.GetTileIdWithoutFlags(rawTileId)
            //                                                              let tile = map.Tiles[tileId]

            //                                                              from polygon in tile.ObjectGroup.Objects
            //                                                              where polygon is TmxHasPoints

            //                                                              select polygon.ToEnumerable().ToList().TrueForAll
            //                                                              (h__TransparentIdentifier4 =>

            //                    {
            //                        UnityEngine.Debug.Log("liudaodelh");
            //                        tuple = new Tuple<TmxObject, TmxTile, uint>(polygon, tile, rawTileId);
            //                        if (!usingUnityLayerOverride)
            //                        {


            //                            return string.Compare(tuple.Item1.Type, chunk.ParentData.ParentLayer.Name, true) == 0;
            //                        }

            //                        return true;
            //                    }))
            //                           select new
            //                           {

            //                               PositionOnMap = map.GetMapPositionAt((int)tuple.Item1.Position.X + chunk.X, (int)tuple.Item1.Position.Y + chunk.Y, tuple.Item2),
            //                               HasPointsInterface = (tuple.Item1 as TmxHasPoints),
            //                               TmxObjectInterface = tuple.Item1,
            //                               IsFlippedDiagnoally = TmxMath.IsTileFlippedDiagonally(tuple.Item3),
            //                               IsFlippedHorizontally = TmxMath.IsTileFlippedHorizontally(tuple.Item3),
            //                               IsFlippedVertically = TmxMath.IsTileFlippedVertically(tuple.Item3),
            //                               TileCenter = new PointF((float)tuple.Item2.TileSize.Width * 0.5f, (float)tuple.Item2.TileSize.Height * 0.5f)
            //                           })
            //     {
            //         List<IntPoint> list = new List<IntPoint>();
            //         SizeF offset = new SizeF(item2.TmxObjectInterface.Position);
            //         PointF[] array = item2.HasPointsInterface.Points.Select((PointF pt) => PointF.Add(pt, offset)).ToArray();
            //         TmxMath.TransformPoints(array, item2.TileCenter, item2.IsFlippedDiagnoally, item2.IsFlippedHorizontally, item2.IsFlippedVertically);
            //         PointF[] array2 = array;
            //         for (int i = 0; i < array2.Length; i++)
            //         {
            //             PointF pointF = array2[i];
            //             float x2 = (float)item2.PositionOnMap.X + pointF.X;
            //             float y2 = (float)item2.PositionOnMap.Y + pointF.Y;
            //             IntPoint item = xfFunc(x2, y2);
            //             list.Add(item);
            //         }
            //         list.Reverse();
            //         clipper.AddPath(list, PolyType.ptSubject, item2.HasPointsInterface.ArePointsClosed());
            //     }
            //     PolyTree polyTree = new PolyTree();
            //     clipper.Execute(ClipType.ctUnion, polyTree, SubjectFillRule, ClipFillRule);

            //     return polyTree;


            ClipperLib.Clipper clipper = new ClipperLib.Clipper();

            // Limit to polygon "type" that matches the collision layer name (unless we are overriding the whole layer to a specific Unity Layer Name)
            bool usingUnityLayerOverride = !String.IsNullOrEmpty(chunk.ParentData.ParentLayer.UnityLayerOverrideName);

            var polygons = from y in Enumerable.Range(0, chunk.Height)
                           from x in Enumerable.Range(0, chunk.Width)
                           let rawTileId = chunk.GetRawTileIdAt(x, y)
                                           where rawTileId != 0
                                           let tileId                       = TmxMath.GetTileIdWithoutFlags(rawTileId)
                                                                   let tile = map.Tiles[tileId]
                                                                              from polygon in tile.ObjectGroup.Objects
                                                                              where (polygon as TmxHasPoints) != null
                                                                              where usingUnityLayerOverride || String.Compare(polygon.Type, chunk.ParentData.ParentLayer.Name, true) == 0
                                                                              select new
            {
                PositionOnMap         = map.GetMapPositionAt(x + chunk.X, y + chunk.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),
            };

            // 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 polygons)
            {
                // 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"
                clipper.AddPath(clipperPolygon, ClipperLib.PolyType.ptSubject, poly.HasPointsInterface.ArePointsClosed());
            }

            ClipperLib.PolyTree solution = new ClipperLib.PolyTree();
            clipper.Execute(ClipperLib.ClipType.ctUnion, solution, LayerClipper.SubjectFillRule, LayerClipper.ClipFillRule);
            return(solution);
        }
        private List <XElement> CreateImportFilesElements(string exportToUnityProjectPath)
        {
            List <XElement> elements = new List <XElement>();

            // Add the mesh file as raw text
            {
                StringWriter objBuilder = BuildObjString();

                XElement mesh =
                    new XElement("ImportMesh",
                                 new XAttribute("filename", this.tmxMap.Name + ".obj"),
                                 StringToBase64String(objBuilder.ToString()));

                elements.Add(mesh);
            }

            {
                // Add all image files as compressed base64 strings
                var imagePaths = from layer in this.tmxMap.Layers
                                 where layer.Visible == true
                                 from rawTileId in layer.TileIds
                                 where rawTileId != 0
                                 let tileId                       = TmxMath.GetTileIdWithoutFlags(rawTileId)
                                                         let tile = this.tmxMap.Tiles[tileId]
                                                                    select tile.TmxImage.Path;
                imagePaths = imagePaths.Distinct();

                // Do not import files if they are already in the project (in the /Assets/ directory of where we're exporting too)
                string unityAssetsDir = Path.Combine(exportToUnityProjectPath, "Assets");

                foreach (string path in imagePaths)
                {
                    // If the copy from location comes from within the project we want to copy to, then don't do it.
                    // This allows us to have tileset images that are alreday in use by the Unity project
                    string saveToAssetsDir = unityAssetsDir.ToLower();
                    string copyFromDir     = path.ToLower();
                    if (copyFromDir.StartsWith(saveToAssetsDir))
                    {
                        // The path to the texture will be WRT to the Unity project root
                        string assetPath = path.Remove(0, exportToUnityProjectPath.Length);
                        assetPath = assetPath.TrimStart('\\');
                        assetPath = assetPath.TrimStart('/');
                        Program.WriteLine("InternalTexture : {0}", assetPath);

                        XElement texture = new XElement("InternalTexture", new XAttribute("assetPath", assetPath));
                        elements.Add(texture);
                    }
                    else
                    {
                        // Note that compression is not available in Unity. Go with Base64 string. Blerg.
                        Program.WriteLine("ImportTexture : will import '{0}' to {1}", path, Path.Combine(unityAssetsDir, "Tiled2Unity\\Textures\\"));
                        XElement texture =
                            new XElement("ImportTexture",
                                         new XAttribute("filename", Path.GetFileName(path)),
                                         FileToBase64String(path));
                        //FileToCompressedBase64String(path));

                        elements.Add(texture);
                    }
                }
            }

            return(elements);
        }
        private StringWriter BuildObjString()
        {
            // Creates the text for a Wavefront OBJ file for the TmxMap
            StringWriter objWriter = new StringWriter();

            // Gather the information for every face
            var faces = from layer in this.tmxMap.Layers
                        where layer.Visible == true
                        where layer.Properties.GetPropertyValueAsBoolean("unity:collisionOnly", false) == false

                        // Draw order forces us to visit tiles in a particular order
                        from y in (this.tmxMap.DrawOrderVertical == 1) ? Enumerable.Range(0, layer.Height) : Enumerable.Range(0, layer.Height).Reverse()
                        from x in (this.tmxMap.DrawOrderHorizontal == 1) ? Enumerable.Range(0, layer.Width) : Enumerable.Range(0, layer.Width).Reverse()

                        let rawTileId = layer.GetRawTileIdAt(x, y)
                                        let tileId = TmxMath.GetTileIdWithoutFlags(rawTileId)
                                                     where tileId != 0
                                                     let fd                                              = TmxMath.IsTileFlippedDiagonally(rawTileId)
                                                                                let fh                   = TmxMath.IsTileFlippedHorizontally(rawTileId)
                                                                                                  let fv = TmxMath.IsTileFlippedVertically(rawTileId)
                                                                                                           let animTile = this.tmxMap.Tiles[tileId]

                                                                                                                          // Enumerate through all frames of a tile. (Tiles without animation are treated as a single frame)
                                                                                                                          from frame in TileFrame.EnumerateFramesFromTile(animTile, this.tmxMap)
                                                                                                                          select new
            {
                LayerName          = layer.UniqueName,
                Vertices           = CalculateFaceVertices(this.tmxMap.GetMapPositionAt(x, y), frame.Tile.TileSize, this.tmxMap.TileHeight, frame.Position_z),
                TextureCoordinates = CalculateFaceTextureCoordinates(frame.Tile, fd, fh, fv),
                ImagePath          = frame.Tile.TmxImage.Path,
                ImageName          = Path.GetFileNameWithoutExtension(frame.Tile.TmxImage.Path),
            };

            // We have all the information we need now to build our list of vertices, texture coords, and grouped faces
            // (Faces are grouped by LayerName.TextureName combination because Wavefront Obj only supports one texture per face)
            objWriter.WriteLine("# Wavefront OBJ file automatically generated by Tiled2Unity");
            objWriter.WriteLine();

            // We may have a ton of vertices so use a set right now
            HashSet <Vector3D> vertexSet = new HashSet <Vector3D>();

            Program.WriteLine("Building face vertices");
            foreach (var face in faces)
            {
                // Index the vertices
                foreach (var v in face.Vertices)
                {
                    vertexSet.Add(v);
                }
            }

            HashSet <PointF> textureCoordinateSet = new HashSet <PointF>();

            Program.WriteLine("Building face texture coordinates");
            foreach (var face in faces)
            {
                // Index the texture coordinates
                foreach (var tc in face.TextureCoordinates)
                {
                    textureCoordinateSet.Add(tc);
                }
            }

            // Write the indexed vertices
            Program.WriteLine("Writing indexed vertices");
            IList <Vector3D> vertices = vertexSet.ToList();

            objWriter.WriteLine("# Vertices (Count = {0})", vertices.Count);
            foreach (var v in vertices)
            {
                objWriter.WriteLine("v {0} {1} {2}", v.X, v.Y, v.Z);
            }
            objWriter.WriteLine();

            // Write the indexed texture coordinates
            Program.WriteLine("Writing indexed texture coordinates");
            IList <PointF> textureCoordinates = textureCoordinateSet.ToList();

            objWriter.WriteLine("# Texture Coorindates (Count = {0})", textureCoordinates.Count);
            foreach (var vt in textureCoordinates)
            {
                objWriter.WriteLine("vt {0} {1}", vt.X, vt.Y);
            }
            objWriter.WriteLine();

            // Write the one indexed normal
            objWriter.WriteLine("# Normal");
            objWriter.WriteLine("vn 0 0 -1");
            objWriter.WriteLine();

            // Group faces by Layer+TileSet
            var groups = from f in faces
                         group f by TiledMapExpoterUtils.UnityFriendlyMeshName(tmxMap, f.LayerName, f.ImageName);

            // Write out the faces
            objWriter.WriteLine("# Groups (Count = {0})", groups.Count());

            // Need dictionaries with index as value.
            var vertexDict   = Enumerable.Range(0, vertices.Count()).ToDictionary(i => vertices[i], i => i);
            var texCoordDict = Enumerable.Range(0, textureCoordinates.Count()).ToDictionary(i => textureCoordinates[i], i => i);

            foreach (var g in groups)
            {
                Program.WriteLine("Writing '{0}' mesh group", g.Key);

                objWriter.WriteLine("g {0}", g.Key);
                foreach (var f in g)
                {
                    objWriter.Write("f ");
                    for (int i = 0; i < 4; ++i)
                    {
                        int vertexIndex            = vertexDict[f.Vertices[i]] + 1;
                        int textureCoordinateIndex = texCoordDict[f.TextureCoordinates[i]] + 1;

                        objWriter.Write(" {0}/{1}/1 ", vertexIndex, textureCoordinateIndex);
                    }
                    objWriter.WriteLine();
                }
            }

            Program.WriteLine("Done writing Wavefront Obj data for '{0}'", tmxMap.Name);

            return(objWriter);
        }
Exemple #25
0
        public uint GetTileIdAt(int x, int y)
        {
            uint tileId = GetRawTileIdAt(x, y);

            return(TmxMath.GetTileIdWithoutFlags(tileId));
        }
Exemple #26
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;
            }

            // 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.UnityLayerOverrideName = tmxLayer.Properties.GetPropertyValueAsString("unity:layer", "");
            tmxLayer.BuildCollisionLayers();

            return(tmxLayer);
        }