Esempio n. 1
0
        ///<summary>
        ///Create and configure main Grid GameObject.
        ///</summary>
        static GameObject CreateGrid(AssetImportContext context, Map map)
        {
            var name = Path.GetFileNameWithoutExtension(context.assetPath);

            // Instantiate a prefab named after the tilemap name, if any.
            var        prefab = PrefabHelper.Load(name, context, map.properties.Length > 0);
            GameObject gameObject;

            if (prefab)
            {
                gameObject = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
                foreach (var component in gameObject.GetComponentsInChildren <MonoBehaviour>())
                {
                    Property.Apply(map.properties, component);
                }
            }
            else
            {
                gameObject = new GameObject(name);
            }

            var grid = gameObject.AddComponent <Grid>();

            gameObject.isStatic = true;

            switch (map.orientation)
            {
            case "orthogonal": grid.cellLayout = CellLayout.Rectangle; break;

            case "isometric":  grid.cellLayout = CellLayout.Isometric; break;

            case "hexagonal":  grid.cellLayout = CellLayout.Hexagon;   break;

            default: throw new NotImplementedException($"Orientation: {map.orientation}");
            }

            // Grid cells are always 1 unit wide; their height respects the aspect ratio.
            grid.cellSize = new Vector3(1f, (float)map.tileheight / map.tilewidth, 1f);

            gameObject.AddComponent <Rigidbody2D>().bodyType = RigidbodyType2D.Static;
            gameObject.AddComponent <CompositeCollider2D>();

            context.AddObjectToAsset("Grid", gameObject);
            context.SetMainObject(gameObject);

            return(gameObject);
        }
Esempio n. 2
0
        ///<summary>
        ///Instantiate a prefab or create a GameObject for each layer.
        ///</summary>
        static GameObject[] CreateLayers(AssetImportContext context, Map map)
        {
            var animators    = new Dictionary <uint, AnimatorController>();
            var layerObjects = new GameObject[map.layers.Length];

            // A layer can be either a tile layer (has chunks), or an object layer (no chunks).
            for (var i = 0; i < layerObjects.Length; ++i)
            {
                var layer = map.layers[i];

                // Instantiate a prefab named after the layer name, if any.
                var prefab = PrefabHelper.Load(layer.name, context, layer.properties.Length > 0);
                if (prefab)
                {
                    layerObjects[i] = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
                    foreach (var component in layerObjects[i].GetComponentsInChildren <MonoBehaviour>())
                    {
                        Property.Apply(layer.properties, component);
                    }
                }
                else
                {
                    layerObjects[i] = new GameObject(layer.name);
                }

                if (layer.chunks.Length > 0)
                {
                    CreateTileLayer(layerObjects[i], map, layer, order: i);
                }
                else
                {
                    CreateObjectLayer(context, layerObjects[i], map, layer, order: i, animators);
                }
                layerObjects[i].isStatic = true;
            }

            return(layerObjects);
        }
Esempio n. 3
0
        ///<summary>Construct a tilemap from Tiled, adding named prefab instances based on Type.</summary>
        public override void OnImportAsset(AssetImportContext context)
        {
            var assetPathPrefix = Path.GetDirectoryName(assetPath) + Path.DirectorySeparatorChar;
            // TODO: Support ../source.tsx
            var tmx = new TMX(XDocument.Load(assetPath).Element("map"), assetPathPrefix);
            // if (tmx.infinite) {
            //throw new NotImplementedException("Infinite: " + tmx.infinite);
            // }
            var layout = tmx.orientation == "orthogonal"
                                ? GridLayout.CellLayout.Rectangle
                                : tmx.orientation == "isometric"
                                        ? GridLayout.CellLayout.Isometric
                                        : GridLayout.CellLayout.Hexagon;

            var gids   = new uint[tmx.layers.Length][][];
            var gidSet = new HashSet <uint>();

            // TODO: & 0x1fffffff the gidSet values from tile gids[]
            for (var i = 0; i < tmx.layers.Length; ++i)
            {
                var layer = tmx.layers[i];
                if (layer.data.chunks != null)                   // Tile layer
                {
                    gids[i] = new uint[layer.data.chunks.Length][];
                    for (var j = 0; j < gids[i].Length; ++j)
                    {
                        gids[i][j] = ParseGIDs(
                            layer.data.encoding,
                            layer.data.compression,
                            layer.data.chunks[j].value,
                            layer.width,
                            layout
                            );
                        gidSet.UnionWith(gids[i][j]);
                    }
                }
                else                     // Object layer
                {
                    foreach (var @object in layer.objects)
                    {
                        gidSet.Add(@object.gid & 0x1fffffff);
                    }
                }
            }

            // Tilesets
            var tiles = new Tile[1];             // Global Tile IDs start from 1

            foreach (var tsx in tmx.tilesets)
            {
                Tileset tileset = null;
                if (tsx.source == null)                   // Embedded tileset
                {
                    tileset = TSXImporter.Load(context, tsx);
                }
                else                     // External tileset
                {
                    var tilesetSource = "Assets" + Path.GetFullPath(assetPathPrefix + tsx.source).Substring(Application.dataPath.Length);
                    tileset = AssetDatabase.LoadAssetAtPath <Tileset>(tilesetSource);
                    context.DependsOnSourceAsset(tilesetSource);
                }
                var tilesetTiles = new Tile[tileset.tiles.Length];
                for (var i = 0; i < tilesetTiles.Length; ++i)
                {
                    if (!gidSet.Contains((uint)(i + tsx.firstgid)))
                    {
                        continue;
                    }
                    tilesetTiles[i] = tileset.tiles[i].Instantiate(tmx.tilewidth);
                    context.AddObjectToAsset($"tile{i + tsx.firstgid:0000}", tilesetTiles[i]);
                    context.AddObjectToAsset($"sprite{i + tsx.firstgid:0000}", tilesetTiles[i].sprite);
                    for (var j = 0; j < tilesetTiles[i].sprites.Length; ++j)
                    {
                        context.AddObjectToAsset($"frame{i + tsx.firstgid:0000}:{j}", tilesetTiles[i].sprites[j]);
                    }
                }
                ArrayUtility.AddRange(ref tiles, tilesetTiles);
            }

            // Grid
            var grid = new GameObject(Path.GetFileNameWithoutExtension(assetPath), typeof(Grid));

            grid.AddComponent <Rigidbody2D>().bodyType = RigidbodyType2D.Static;
            grid.isStatic = true;
            grid.GetComponent <Grid>().cellLayout = layout;
            grid.GetComponent <Grid>().cellSize   = new Vector3(1f, (float)tmx.tileheight / tmx.tilewidth, 1f);
            context.AddObjectToAsset("grid", grid);
            context.SetMainObject(grid);
            var collider = grid.AddComponent <CompositeCollider2D>();

            collider.generationType = CompositeCollider2D.GenerationType.Manual;

            // Layers
            PrefabHelper.cache.Clear();
            for (var i = 0; i < tmx.layers.Length; ++i)
            {
                var layer       = tmx.layers[i];
                var layerObject = new GameObject(layer.name);
                layerObject.transform.parent = grid.transform;
                layerObject.isStatic         = true;

                // Tile layer
                if (layer.data.chunks != null)
                {
                    // Tilemap
                    var tilemap  = layerObject.AddComponent <Tilemap>();
                    var renderer = layerObject.AddComponent <TilemapRenderer>();
                    layerObject.AddComponent <TilemapCollider2D>().usedByComposite = true;
                    tilemap.color             = new Color(1f, 1f, 1f, layer.opacity);
                    tilemap.orientation       = layout == GridLayout.CellLayout.Hexagon ? Tilemap.Orientation.Custom : Tilemap.Orientation.XY;
                    tilemap.orientationMatrix = Matrix4x4.TRS(
                        Vector3.zero,
                        Quaternion.Euler(0f, 180f, 180f),
                        Vector3.one
                        );
                    tilemap.transform.localScale = layout == GridLayout.CellLayout.Hexagon ? new Vector3(1f, -1f, 1f) : Vector3.one;
                    // Chunks
                    for (var j = 0; j < layer.data.chunks.Length; ++j)
                    {
                        var layerTiles = new Tile[gids[i][j].Length];
                        for (var k = 0; k < layerTiles.Length; ++k)
                        {
                            layerTiles[k] = tiles[gids[i][j][k] & 0x1ffffff];                             // 3 MSB are for flipping
                        }
                        var size   = new Vector3Int(layer.data.chunks[j].width, layer.data.chunks[j].height, 1);
                        var bounds = new BoundsInt(
                            new Vector3Int(
                                layer.width - layer.data.chunks[j].width + layer.data.chunks[j].x,
                                layer.height - layer.data.chunks[j].height - layer.data.chunks[j].y,
                                0
                                ),
                            size);
                        tilemap.SetTilesBlock(bounds, layerTiles);

                        // Flipped tiles
                        for (var k = 0; k < gids[i][j].Length; ++k)
                        {
                            var diagonal   = (gids[i][j][k] >> 29) & 1;
                            var vertical   = (gids[i][j][k] >> 30) & 1;
                            var horizontal = (gids[i][j][k] >> 31) & 1;
                            var flips      = new Vector4(diagonal, vertical, horizontal, 0);
                            if (flips.sqrMagnitude > 0f)
                            {
                                var position = new Vector3Int(
                                    layer.width - layer.data.chunks[j].width + k % layer.data.chunks[j].width,
                                    layer.height - layer.data.chunks[j].height + k / layer.data.chunks[j].width,
                                    0
                                    );
                                var transform = Matrix4x4.TRS(
                                    Vector3.zero,
                                    Quaternion.AngleAxis(diagonal * 180, new Vector3(1, 1, 0)),
                                    Vector3.one - (diagonal == 1 ? new Vector3(flips.y, flips.z, flips.w) : new Vector3(flips.z, flips.y, flips.w)) * 2
                                    );
                                tilemap.SetTransformMatrix(position, transform);
                            }
                        }
                    }


                    renderer.sortOrder    = layout == GridLayout.CellLayout.Hexagon ? TilemapRenderer.SortOrder.BottomLeft : TilemapRenderer.SortOrder.TopLeft;
                    renderer.sortingOrder = i;

                    // Object layer
                }
                else
                {
                    var objects = layer.objects;                    //layer.Elements("object").ToArray();
                    foreach (var @object in objects)
                    {
                        var        tile = tiles[@object.gid & 0x1fffffff];
                        string     icon = null;
                        GameObject gameObject;                         // Doubles as prefab when object has type

                        // Default instantiation when object has no set type
                        if (string.IsNullOrEmpty(@object.type))
                        {
                            gameObject = new GameObject($"{@object.name} {@object.id}".Trim());
                            icon       = "sv_label_0";

                            // Warn instantiation when object has type but no prefab was found
                        }
                        else if (null == (gameObject = PrefabHelper.Load(@object.type, context)))
                        {
                            var gameObjectName = string.IsNullOrEmpty(@object.name) ? @object.type : @object.name;
                            gameObject = new GameObject($"{gameObjectName} {@object.id}".Trim());
                            icon       = "sv_label_6";

                            // Prefab instantiation based on object type
                        }
                        else
                        {
                            gameObject      = PrefabUtility.InstantiatePrefab(gameObject) as GameObject;
                            gameObject.name = $"{@object.name} {@object.id}".Trim();
                            foreach (var component in gameObject.GetComponentsInChildren <MonoBehaviour>())
                            {
                                ApplyProperties(@object.properties, component);
                            }
                        }

                        gameObject.transform.parent = layerObject.transform;

                        // Object sprite
                        var sprite = tile?.sprite;
                        if (sprite)
                        {
                            var diagonal   = ((@object.gid >> 29) & 1) == 1 ? true : false;
                            var vertical   = ((@object.gid >> 30) & 1) == 1 ? true : false;
                            var horizontal = ((@object.gid >> 31) & 1) == 1 ? true : false;
                            gameObject.transform.localRotation *= Quaternion.Euler(0f, 0f, [email protected]);
                            gameObject.transform.localRotation *= Quaternion.Euler(vertical ? 180f : 0f, horizontal ? 180f : 0f, 0f);
                            gameObject.transform.localPosition  = new Vector3(@object.x / tmx.tilewidth, [email protected] / tmx.tileheight + tmx.height, 0);
                            gameObject.transform.localPosition += horizontal ? -gameObject.transform.right * @object.width / tmx.tilewidth : Vector3.zero;
                            gameObject.transform.localPosition += vertical ? -gameObject.transform.up * @object.height / tmx.tileheight : Vector3.zero;
                            var renderer = new GameObject("Renderer").AddComponent <SpriteRenderer>();
                            renderer.transform.SetParent(gameObject.transform, worldPositionStays: false);
                            renderer.sprite                  = sprite;
                            renderer.sortingOrder            = i;
                            renderer.spriteSortPoint         = SpriteSortPoint.Pivot;
                            renderer.drawMode                = SpriteDrawMode.Sliced;              // HACK: Makes renderer.size work
                            renderer.size                    = new Vector2(@object.width, @object.height) / tmx.tilewidth;
                            renderer.color                   = new Color(1f, 1f, 1f, layer.opacity);
                            renderer.transform.localPosition = new Vector3(@object.width / tmx.tilewidth / 2f, @object.height / tmx.tileheight / 2f);
                        }
                        else
                        {
                            gameObject.transform.localPosition =
                                new Vector3(@object.x / tmx.tileheight, [email protected] / tmx.tileheight + tmx.height - @object.height / tmx.tileheight, 0);
                        }

                        // Icon
                        if (icon != null)
                        {
                            InternalEditorGUIHelper.SetIconForObject(
                                gameObject,
                                EditorGUIUtility.IconContent(icon).image
                                );
                        }
                    }
                }
            }

            collider.generationType = CompositeCollider2D.GenerationType.Synchronous;
        }
Esempio n. 4
0
        ///<summary>
        ///Load prefab based on object or tile type, if any, or create a GameObject otherwise.
        ///</summary>
        static GameObject CreateObject(
            AssetImportContext context,
            TMX.Layer.Object @object,
            Tile tile
            )
        {
            var tileName = tile?.prefab ? tile.prefab.name : string.Empty;
            var name     = $"{@object.name ?? @object.type ?? tileName}";

            name = $"{name} {@object.id}".Trim();
            GameObject gameObject = null;
            var        properties = Property.Merge(@object.properties, tile?.properties);
            var        icon       = string.Empty;

            if (!string.IsNullOrEmpty(@object.type))
            {
                // Instantiate prefab based on object type.
                var prefab = PrefabHelper.Load(@object.type, context);
                if (prefab)
                {
                    gameObject = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
                }
            }
            else if (tile?.prefab)
            {
                // Instantiate GameObject based on tile type.
                gameObject = PrefabUtility.InstantiatePrefab(tile.prefab) as GameObject;
            }
            else
            {
                // Default instantiation when object and tile have no set type
                gameObject = new GameObject(name);
                icon       = "sv_label_0";
            }

            if (gameObject != null)
            {
                // Apply properties to all behaviours.
                gameObject.name = name;
                var components = gameObject.GetComponentsInChildren <MonoBehaviour>();
                foreach (var component in components)
                {
                    Property.Apply(properties, component);
                }
            }
            else
            {
                // Warn on instantiation when object has type but no prefab was found.
                gameObject = new GameObject(name);
                icon       = "sv_label_6";
            }

            // Apply icon to GameObject, if any.
            if (!string.IsNullOrEmpty(icon))
            {
                InternalEditorGUIHelper.SetIconForObject(
                    gameObject,
                    EditorGUIUtility.IconContent(icon).image
                    );
            }

            return(gameObject);
        }