static TMX.Object ApplyTemplate(TMX.Object mapObject, out ImportedTileset replacementTileset)
        {
            // Template path seems to be relative to the TMX
            string templatePath = Path.GetFullPath(Path.Combine(TiledTMXImporter.s_tmxParentFolder, mapObject.template));

            ImportedTemplate importedTemplate;

            if (s_importedTemplates.ContainsKey(templatePath))
            {
                importedTemplate = s_importedTemplates[templatePath];
            }
            else
            {
                importedTemplate = TiledTXImporter.LoadTXFile(templatePath, TiledTMXImporter.s_tilesetDir, TiledTMXImporter.s_cellWidth, TiledTMXImporter.s_cellHeight, TiledTMXImporter.s_pixelsPerUnit);
                s_importedTemplates.Add(templatePath, importedTemplate);
            }

            if (!mapObject.gid.HasValue)
            {
                replacementTileset = importedTemplate.m_importedTileset;
            }
            else
            {
                replacementTileset = null; // If the instance has a gid, assume it uses the normal map tilesets
            }
            return(mapObject.GetVersionWithTemplateApplied(importedTemplate.m_template.templateObject));
        }
Beispiel #2
0
        public static void FindTileDataAndMatrix(uint gid, ImportedTileset[] importedTilesets, int cellWidth, int cellHeight,
                                                 out ImportedTile importedTile, out TSX.Tile tilesetTile, out Matrix4x4 matrix)
        {
            importedTile = null;
            tilesetTile  = null;
            matrix       = Matrix4x4.identity;

            bool flippedHorizontally = (gid & FLIPPED_HORIZONTALLY_FLAG) != 0;
            bool flippedVertically   = (gid & FLIPPED_VERTICALLY_FLAG) != 0;
            bool flippedDiagonally   = (gid & FLIPPED_DIAGONALLY_FLAG) != 0;

            gid &= ~(FLIPPED_HORIZONTALLY_FLAG | FLIPPED_VERTICALLY_FLAG | FLIPPED_DIAGONALLY_FLAG);

            ImportedTileset tilesetContainingID = null;

            for (int j = importedTilesets.Length - 1; j >= 0; --j)
            {
                int firstGID = importedTilesets[j].firstGID;
                if (firstGID <= gid)
                {
                    tilesetContainingID = importedTilesets[j];
                    break;
                }
            }

            if (tilesetContainingID != null)
            {
                int relativeID = (int)gid - tilesetContainingID.firstGID;

                if (tilesetContainingID.tileset.IsSingleImageTileset())
                {
                    // A single-image-tileset will just order tiles from 0-n
                    importedTile = tilesetContainingID.tiles[relativeID];
                    tilesetTile  = null;
                }
                else
                {
                    for (int t = 0; t < tilesetContainingID.tileset.tiles.Length; t++)
                    {
                        TSX.Tile tile = tilesetContainingID.tileset.tiles[t];
                        int      id   = tile.id;
                        if (id == relativeID)
                        {
                            importedTile = tilesetContainingID.tiles[t];
                            tilesetTile  = tile;
                            break;
                        }
                    }
                }

                if (importedTile != null)
                {
                    if (importedTile.tile == null) // Load the tile asset if we haven't already
                    {
                        importedTile.tile = AssetDatabase.LoadAssetAtPath <Tile>(importedTile.path);
                    }
                    if (flippedHorizontally || flippedVertically || flippedDiagonally)
                    {
                        if (flippedDiagonally)
                        {
                            matrix = Matrix4x4.Rotate(Quaternion.Euler(0.0f, 0.0f, 90.0f));
                            matrix = Matrix4x4.Scale(new Vector3(1.0f, -1.0f, 1.0f)) * matrix;
                        }

                        if (flippedHorizontally)
                        {
                            matrix = Matrix4x4.Scale(new Vector3(-1.0f, 1.0f, 1.0f)) * matrix;
                        }
                        if (flippedVertically)
                        {
                            matrix = Matrix4x4.Scale(new Vector3(1.0f, -1.0f, 1.0f)) * matrix;
                        }

                        Rect rect = importedTile.tile.sprite.rect;
                        rect.x = -cellWidth * 0.5f;
                        rect.y = -cellHeight * 0.5f;

                        Vector2[] corners = new Vector2[4] {
                            new Vector2(rect.x, rect.y),
                            new Vector2(rect.x + rect.width, rect.y),
                            new Vector2(rect.x, rect.y + rect.height),
                            new Vector2(rect.x + rect.width, rect.y + rect.height)
                        };

                        for (int i = 0; i < corners.Length; i++)
                        {
                            corners[i] = matrix * corners[i];
                        }
                        Vector2 bottomLeftCorner = corners[0];
                        for (int i = 1; i < corners.Length; i++)
                        {
                            if (corners[i].x < bottomLeftCorner.x)
                            {
                                bottomLeftCorner.x = corners[i].x;
                            }
                            if (corners[i].y < bottomLeftCorner.y)
                            {
                                bottomLeftCorner.y = corners[i].y;
                            }
                        }
                        Vector2 offsetNeededUnits = new Vector2(-0.5f, -0.5f) - new Vector2(bottomLeftCorner.x / (float)cellWidth, bottomLeftCorner.y / (float)cellHeight);
                        matrix = Matrix4x4.Translate(offsetNeededUnits) * matrix;
                    }
                }
            }
        }
Beispiel #3
0
 public ImportedTemplate(TXTypes.Template template, ImportedTileset tileset)
 {
     m_template        = template;
     m_importedTileset = tileset;
 }
Beispiel #4
0
        public static bool ImportTMXFile(string path, string tilesetDir, Grid targetGrid)
        {
            string tmxParentFolder = Path.GetDirectoryName(path);
            string filename        = Path.GetFileNameWithoutExtension(path);

            TMX.Map map = ImportUtils.ReadXMLIntoObject <TMX.Map>(path);
            if (map == null)
            {
                return(false);
            }
            if (map.backgroundcolor != null)
            {
                Color backgroundColor;
                if (ColorUtility.TryParseHtmlString(map.backgroundcolor, out backgroundColor))
                {
                    Camera.main.backgroundColor = backgroundColor;
                }
            }
            if (map.tilesets != null)
            {
                // First we need to load (or import) all the tilesets referenced by the TMX file...
                int cellWidth     = map.tilewidth;
                int cellHeight    = map.tileheight;
                int pixelsPerUnit = Mathf.Max(map.tilewidth, map.tileheight);
                ImportedTileset[] importedTilesets = new ImportedTileset[map.tilesets.Length];
                for (int i = 0; i < map.tilesets.Length; i++)
                {
                    importedTilesets[i] = TiledTSXImporter.ImportFromTilesetReference(map.tilesets[i], tmxParentFolder, tilesetDir, cellWidth, cellHeight, pixelsPerUnit);
                    if (importedTilesets[i] == null || importedTilesets[i].tiles == null || importedTilesets[i].tiles[0] == null)
                    {
                        Debug.LogError("Imported tileset is incomplete");
                        return(false);
                    }
                }


                // Set up the Grid to store everything in
                GameObject newGrid = null;
                if (targetGrid != null)
                {
                    newGrid = targetGrid.gameObject;
                    for (int i = newGrid.transform.childCount - 1; i >= 0; --i)
                    {
                        Undo.DestroyObjectImmediate(newGrid.transform.GetChild(i).gameObject);
                    }
                }
                else
                {
                    newGrid = new GameObject(filename, typeof(Grid));
                    newGrid.GetComponent <Grid>().cellSize = new Vector3(1.0f, 1.0f, 0.0f);
                    Undo.RegisterCreatedObjectUndo(newGrid, "Import map to new Grid");
                }

                ITilemapImportOperation[] importOperations = ImportUtils.GetObjectsThatImplementInterface <ITilemapImportOperation>();
                TilemapRenderer.SortOrder sortOrder        = TilemapRenderer.SortOrder.TopLeft;
                if (map.renderorder.Equals("right-down"))
                {
                    sortOrder = TilemapRenderer.SortOrder.TopLeft;
                }
                else if (map.renderorder.Equals("right-up"))
                {
                    sortOrder = TilemapRenderer.SortOrder.BottomLeft;
                }
                else if (map.renderorder.Equals("left-down"))
                {
                    sortOrder = TilemapRenderer.SortOrder.TopRight;
                }
                else if (map.renderorder.Equals("left-up"))
                {
                    sortOrder = TilemapRenderer.SortOrder.BottomRight;
                }
                // Load all the tile layers
                if (map.layers != null)
                {
                    for (int i = 0; i < map.layers.Length; i++)
                    {
                        TMX.Layer layer = map.layers[i];

                        bool success = ImportTileLayer(layer, newGrid, i, importedTilesets, importOperations, sortOrder, cellWidth, cellHeight, map.infinite);
                        if (!success)
                        {
                            return(false);
                        }
                    }
                }

                Dictionary <string, ImportedTemplate> importedTemplates = new Dictionary <string, ImportedTemplate>();

                // Load all the objects
                if (map.objectgroups != null)
                {
                    for (int g = 0; g < map.objectgroups.Length; g++)
                    {
                        TMX.ObjectGroup objectGroup = map.objectgroups[g];

                        if (objectGroup != null && objectGroup.objects != null && objectGroup.objects.Length > 0)
                        {
                            GameObject newObjectLayer = new GameObject(objectGroup.name);
                            newObjectLayer.transform.SetParent(newGrid.transform, false);
                            Undo.RegisterCreatedObjectUndo(newObjectLayer, "Import object layer");

                            int sortingLayer = (map.layers == null ? 0 : map.layers.Length) + g;

                            for (int i = 0; i < objectGroup.objects.Length; i++)
                            {
                                TMX.Object mapObject = objectGroup.objects[i];

                                bool success = ImportMapObject(mapObject, importedTilesets, importedTemplates, newObjectLayer, map.tilewidth, map.tileheight, sortingLayer, importOperations, tilesetDir, cellWidth, cellHeight, pixelsPerUnit, tmxParentFolder);
                                if (!success)
                                {
                                    return(false);
                                }
                            }
                            Color objectColour = new Color(1.0f, 1.0f, 1.0f, 1.0f);
                            if (objectGroup.color != null)
                            {
                                ColorUtility.TryParseHtmlString(objectGroup.color, out objectColour);
                            }
                            if (objectGroup.opacity != 1.0f)
                            {
                                objectColour.a = objectGroup.opacity;
                            }
                            SpriteRenderer[] renderers = newObjectLayer.GetComponentsInChildren <SpriteRenderer>();
                            foreach (SpriteRenderer r in renderers)
                            {
                                r.color = objectColour;
                            }
                            if (!objectGroup.visible)
                            {
                                foreach (SpriteRenderer r in renderers)
                                {
                                    r.enabled = false;
                                }
                            }

                            IDictionary <string, string> properties = (objectGroup.properties == null ? new Dictionary <string, string>() : objectGroup.properties.ToDictionary());

                            foreach (ITilemapImportOperation operation in importOperations)
                            {
                                operation.HandleCustomProperties(newObjectLayer, properties);
                            }
                        }
                    }
                }
            }

            return(true);
        }
Beispiel #5
0
        static bool ImportMapObject(TMX.Object mapObject, ImportedTileset[] importedTilesets, Dictionary <string, ImportedTemplate> importedTemplates, GameObject newObjectLayer, int mapTileWidth, int mapTileHeight, int sortingLayer,
                                    ITilemapImportOperation[] importOperations, string tilesetDir, int cellWidth, int cellHeight, int pixelsPerUnit, string tmxParentFolder)
        {
            ImportedTileset replacementTileset = null;

            if (mapObject.template != null)
            {
                // Fill out empty object fields with data from the template.
                // The template could have a tile from it's own tileset reference, so in that case, use the template tileset instead, and the template object GID
                TMX.Object combinedMapObject = ApplyTemplate(mapObject, tmxParentFolder, tilesetDir, cellWidth, cellHeight, pixelsPerUnit, importedTemplates, out replacementTileset);

                if (combinedMapObject == null)
                {
                    Debug.LogError("Could not load template for map object " + mapObject);
                    return(false);
                }
                else
                {
                    mapObject = combinedMapObject;
                }
            }
            mapObject.InitialiseUnsetValues(); // We need special code to set defaults here, because setting them before merging with a template would give incorrect results.

            // Use the template's tileset (and the gid that's been set by ApplyTemplate)
            if (replacementTileset != null)
            {
                importedTilesets = new ImportedTileset[] { replacementTileset };
            }

            ImportedTile importedTile;

            TSX.Tile  tilesetTile; // Unused
            Matrix4x4 matrix;

            TiledUtils.FindTileDataAndMatrix(mapObject.gid.Value, importedTilesets, cellWidth, cellHeight, out importedTile, out tilesetTile, out matrix);

            Vector2 pixelsToUnits = new Vector2(1.0f / mapTileWidth, -1.0f / mapTileHeight);

            GameObject newObject = new GameObject(mapObject.name);

            newObject.transform.SetParent(newObjectLayer.transform, false);

            // So we gain the tile rotation/flipping
            newObject.transform.FromMatrix(matrix);

            Vector2 corner = Vector2.Scale(new Vector2(mapObject.x.Value, mapObject.y.Value), pixelsToUnits);

            if (importedTile != null)
            {
                Tile    unityTile          = importedTile.tile;
                Vector2 pivotProportion    = new Vector2(unityTile.sprite.pivot.x / unityTile.sprite.rect.width, unityTile.sprite.pivot.y / unityTile.sprite.rect.height);
                Vector3 pivotWorldPosition = corner + Vector2.Scale(new Vector2(mapObject.width.Value * pivotProportion.x, mapObject.height.Value * -pivotProportion.y), pixelsToUnits);
                newObject.transform.localPosition += pivotWorldPosition;

                SpriteRenderer renderer = newObject.AddComponent <SpriteRenderer>();
                renderer.sprite       = unityTile.sprite;
                renderer.sortingOrder = sortingLayer;
                if (unityTile.colliderType == Tile.ColliderType.Sprite)
                {
                    newObject.AddComponent <PolygonCollider2D>();
                }
                else if (unityTile.colliderType == Tile.ColliderType.Grid)
                {
                    newObject.AddComponent <BoxCollider2D>();
                }
                Vector2 scale = new Vector2(mapObject.width.Value / unityTile.sprite.rect.width, mapObject.height.Value / unityTile.sprite.rect.height);
                newObject.transform.localScale = Vector3.Scale(newObject.transform.localScale, new Vector3(scale.x, scale.y, 1.0f));
            }
            else
            {
                Vector3 pivotWorldPosition = corner + Vector2.Scale(new Vector2(mapObject.width.Value * 0.5f, mapObject.height.Value * 0.5f), pixelsToUnits);
                newObject.transform.localPosition += pivotWorldPosition;
                // If no tile used, must be a non-tile object of some sort (collision or text)
                if (mapObject.ellipse != null)
                {
                    EllipseCollider2D collider = newObject.AddComponent <EllipseCollider2D>();
                    collider.RadiusX = (mapObject.width.Value * 0.5f) / mapTileWidth;
                    collider.RadiusY = (mapObject.height.Value * 0.5f) / mapTileHeight;
                }
                else if (mapObject.polygon != null)
                {
                    PolygonCollider2D collider = newObject.AddComponent <PolygonCollider2D>();
                    string            points   = mapObject.polygon.points;
                    collider.points = ImportUtils.PointsFromString(points, pixelsToUnits);
                }
                else if (mapObject.polyline != null)
                {
                    EdgeCollider2D collider = newObject.AddComponent <EdgeCollider2D>();
                    string         points   = mapObject.polyline.points;
                    collider.points = ImportUtils.PointsFromString(points, pixelsToUnits);
                }
                else if (mapObject.text != null)
                {
                    TextMesh textMesh = newObject.AddComponent <TextMesh>();
                    textMesh.text   = mapObject.text.text;
                    textMesh.anchor = TextAnchor.MiddleCenter;

                    Color color = Color.white;
                    if (mapObject.text.color != null)
                    {
                        ColorUtility.TryParseHtmlString(mapObject.text.color, out color);
                    }
                    textMesh.color = color;

                    // Saving an OS font as an asset in unity (through script) is seemingly impossible right now in a platform independent way
                    // So we'll skip fonts for now

                    textMesh.fontSize = (int)mapObject.text.pixelsize; // Guess a good resolution for the font
                    float targetWorldTextHeight = (float)mapObject.text.pixelsize / (float)mapTileHeight;
                    textMesh.characterSize = targetWorldTextHeight * 10.0f / textMesh.fontSize;

                    Renderer renderer = textMesh.gameObject.GetComponent <MeshRenderer>();
                    renderer.sortingOrder   = sortingLayer;
                    renderer.sortingLayerID = SortingLayer.GetLayerValueFromName("Default");
                }
                else
                {
                    // Regular box collision
                    BoxCollider2D collider = newObject.AddComponent <BoxCollider2D>();
                    collider.size = new Vector2(mapObject.width.Value / mapTileWidth, mapObject.height.Value / mapTileHeight);
                }
            }

            if (mapObject.rotation != 0.0f)
            {
                newObject.transform.RotateAround(corner, new Vector3(0.0f, 0.0f, 1.0f), -mapObject.rotation.Value);
            }

            if (mapObject.visible == false)
            {
                Renderer renderer = newObject.GetComponent <Renderer>();
                if (renderer != null)
                {
                    renderer.enabled = false;
                }
            }

            IDictionary <string, string> properties = (mapObject.properties == null ? new Dictionary <string, string>() : mapObject.properties.ToDictionary());

            foreach (ITilemapImportOperation operation in importOperations)
            {
                operation.HandleCustomProperties(newObject, properties);
            }
            return(true);
        }