示例#1
0
        ///<summary>
        ///Create a GameObject for each Tile with a defined type and thus potentially a prefab.
        ///</summary>
        static void CreateTileObjects(
            Map map,
            Map.Layer layer,
            Map.Layer.Chunk chunk,
            GameObject layerObject
            )
        {
            var chunkPosition = new Vector3Int(chunk.x, layer.height - chunk.height - chunk.y, 0);

            for (var k = 0; k < chunk.gids.Length; ++k)
            {
                var gid  = chunk.gids[k];
                var tile = map.tiles[gid & 0x1ffffff];
                if (!tile?.prefab)
                {
                    continue;
                }

                // The 3 most significant bits indicate in what way the tile should be flipped.
                var diagonal   = (gid >> 29) & 1;
                var vertical   = (gid >> 30) & 1;
                var horizontal = (gid >> 31) & 1;

                var position = chunkPosition + new Vector3Int(k % chunk.width, k / chunk.width, 0);

                // Since a tile's GameObject is instantiated automatically in Edit Mode and *again*
                // in Play Mode, we can't use the built in approach, and instead have to
                // handle instantiation ourselves to avoid duplicate GameObjects.
                var gameObject = PrefabUtility.InstantiatePrefab(
                    tile.prefab, layerObject.transform
                    ) as GameObject;
                if (gameObject)
                {
                    gameObject.name += $" {position.x},{position.y}";
                    gameObject.transform.localPosition = position;
                    if (vertical == 1)
                    {
                        gameObject.transform.localRotation *= Quaternion.Euler(180f, 0f, 0f);
                        gameObject.transform.localPosition -= gameObject.transform.up;
                    }
                    if (horizontal == 1)
                    {
                        gameObject.transform.localRotation *= Quaternion.Euler(0f, 180f, 0f);
                        gameObject.transform.localPosition -= gameObject.transform.right;
                    }
                    if (diagonal == 1)
                    {
                        gameObject.transform.localRotation *=
                            Quaternion.AngleAxis(180f, new Vector3(-1f, 1f, 0f));
                        gameObject.transform.localPosition -= gameObject.transform.up;
                        gameObject.transform.localPosition -= gameObject.transform.right;
                    }
                    foreach (var component in gameObject.GetComponentsInChildren <MonoBehaviour>())
                    {
                        Property.Apply(tile.properties, component);
                    }
                }
            }
        }
示例#2
0
        ///<summary>
        ///Get an array of all tiles in a chunk.
        ///</summary>
        static Tile[] GetTiles(Map map, Map.Layer layer, Map.Layer.Chunk chunk)
        {
            var tiles = new Tile[chunk.gids.Length];

            for (var k = 0; k < tiles.Length; ++k)
            {
                tiles[k] = map.tiles[chunk.gids[k] & 0x1ffffff];
            }

            return(tiles);
        }
示例#3
0
        ///<summary>
        ///Add and configure a Tilemap component for a layer.
        ///</summary>
        static void CreateTileLayer(
            GameObject layerObject,
            Map map,
            Map.Layer layer,
            int order
            )
        {
            var tilemap  = layerObject.AddComponent <UnityEngine.Tilemaps.Tilemap>();
            var renderer = layerObject.AddComponent <TilemapRenderer>();

            layerObject.AddComponent <TilemapCollider2D>().usedByComposite = true;
            tilemap.color         = new Color(1f, 1f, 1f, layer.opacity);
            renderer.sortingOrder = order;

            // Hexagonal maps have to be rotated 180 degrees, flipped horizontally, and the tilemap
            // object has to be flipped vertically. Because of this, the sort order is also weird :/
            if (map.orientation == "hexagonal")
            {
                tilemap.orientation          = UnityEngine.Tilemaps.Tilemap.Orientation.Custom;
                tilemap.orientationMatrix    = Matrix4x4.Rotate(Quaternion.Euler(0f, 180f, 180f));
                tilemap.transform.localScale = new Vector3(1f, -1f, 1f);
                renderer.sortOrder           = TilemapRenderer.SortOrder.BottomLeft;
            }
            else
            {
                renderer.sortOrder = TilemapRenderer.SortOrder.TopLeft;
            }

            // Tiled generally defines Y-positive as down, whereas Unity defines it as up.
            // This effectively means that all positions need to have their Y-component reversed.
            for (var j = 0; j < layer.chunks.Length; ++j)
            {
                var chunk    = layer.chunks[j];
                var position = new Vector3Int(chunk.x, layer.height - chunk.height - chunk.y, 0);
                var size     = new Vector3Int(chunk.width, chunk.height, 1);
                var bounds   = new BoundsInt(position, size);
                tilemap.SetTilesBlock(bounds, GetTiles(map, layer, chunk));
                FlipTiles(tilemap, layer, chunk);
                CreateTileObjects(map, layer, chunk, layerObject);
            }
        }
示例#4
0
        ///<summary>
        ///Flip all tiles in a chunk according to their 3 most significant flip bits, if any.
        ///</summary>
        static void FlipTiles(Tilemap tilemap, Map.Layer layer, Map.Layer.Chunk chunk)
        {
            var chunkPosition = new Vector3Int(chunk.x, layer.height - chunk.height - chunk.y, 0);

            for (var k = 0; k < chunk.gids.Length; ++k)
            {
                var gid = chunk.gids[k];

                // The 3 most significant bits indicate in what way the tile should be flipped.
                if (gid >> 29 == 0)
                {
                    continue;
                }
                var diagonal   = (gid >> 29) & 1;
                var vertical   = (gid >> 30) & 1;
                var horizontal = (gid >> 31) & 1;

                var position = chunkPosition + new Vector3Int(k % chunk.width, k / chunk.width, 0);
                var rotation = Quaternion.identity;

                // Flip tiles along X, Y, and diagonally based on the flip flags.
                if (vertical == 1)
                {
                    rotation *= Quaternion.Euler(180f, 0f, 0f);
                }
                if (horizontal == 1)
                {
                    rotation *= Quaternion.Euler(0f, 180f, 0f);
                }
                if (diagonal == 1)
                {
                    rotation *= Quaternion.AngleAxis(180f, new Vector3(-1f, 1f, 0f));
                }
                var transform = Matrix4x4.TRS(pos: Vector3.zero, rotation, s: Vector3.one);
                tilemap.SetTransformMatrix(position, transform);
            }
        }
示例#5
0
        ///<summary>
        ///Create a GameObject for each Tiled object in layer.
        ///</summary>
        static void CreateObjectLayer(
            AssetImportContext context,
            GameObject layerObject,
            Map map,
            Map.Layer layer,
            int order,
            Dictionary <uint, AnimatorController> animators
            )
        {
            foreach (var @object in layer.objects)
            {
                var tile       = map.tiles[(int)(@object.gid & 0x1fffffff)];
                var sprite     = tile?.sprite;
                var gameObject = CreateObject(context, @object, tile);
                var size       =
                    new Vector2(@object.width / map.tilewidth, @object.height / map.tileheight);

                // Since Tiled's up is Y-negative while Unity's is Y-positive, the Y position is
                // effectively reversed.
                gameObject.transform.parent        = layerObject.transform;
                gameObject.transform.localPosition = new Vector3(
                    @object.x / map.tilewidth,
                    [email protected] / map.tileheight + map.height
                    );

                // Tiled's rotation is clockwise, while Unity's is anticlockwise.
                gameObject.transform.localRotation *= Quaternion.Euler(0f, 0f, [email protected]);

                // Continue early if there's no tile or sprite associated with the object.
                if (!sprite)
                {
                    gameObject.transform.localPosition += Vector3.down * size.y;
                    continue;
                }

                // Position children of the GameObject at the center of the object.
                var childPosition = size / 2f;

                // Rotate and realign the object based on 3 most significant flip bits.
                //var diagonal   = ((@object.gid >> 29) & 1) == 1;
                var vertical   = ((@object.gid >> 30) & 1) == 1;
                var horizontal = ((@object.gid >> 31) & 1) == 1;
                if (vertical)
                {
                    gameObject.transform.localRotation *= Quaternion.Euler(180f, 0f, 0f);
                    gameObject.transform.localPosition -= gameObject.transform.up * size.y;
                }
                if (horizontal)
                {
                    gameObject.transform.localRotation *= Quaternion.Euler(0f, 180f, 0f);
                    gameObject.transform.localPosition -= gameObject.transform.right * size.x;
                }

                // Create a SpriteRenderer child object, and scale it according to object size.
                var renderer = new GameObject("Renderer").AddComponent <SpriteRenderer>();
                renderer.transform.SetParent(gameObject.transform);
                renderer.transform.localPosition = childPosition;
                renderer.transform.localRotation = Quaternion.identity;
                renderer.sprite          = sprite;
                renderer.sortingOrder    = order;
                renderer.spriteSortPoint = SpriteSortPoint.Pivot;
                renderer.drawMode        = SpriteDrawMode.Sliced;          // HACK: Makes renderer.size work
                renderer.size            = new Vector2(@object.width, @object.height) / map.tilewidth;
                renderer.color           = new Color(1f, 1f, 1f, layer.opacity);
                renderer.maskInteraction = SpriteMaskInteraction.VisibleOutsideMask;

                // A new animator controller is created for each unique tile, if necessary.
                if (tile.frames.Length > 1)
                {
                    if (!animators.TryGetValue(@object.gid & 0x1fffffff, out var controller))
                    {
                        controller = CreateAnimatorController(context, $"{@object.gid}", tile);
                        animators[@object.gid & 0x1fffffff] = controller;
                    }
                    var animator = renderer.gameObject.AddComponent <Animator>();
                    animator.runtimeAnimatorController = controller;

                    // Apply animations to all components.
                    foreach (var component in gameObject.GetComponentsInChildren <MonoBehaviour>())
                    {
                        ApplyAnimation(context, controller, tile.frames, component);
                    }
                }

                // A Collider child object is created for each collision shape defined in Tiled.
                if (tile.colliderType == Tile.ColliderType.Sprite)
                {
                    var shapeCount = sprite.GetPhysicsShapeCount();
                    for (var j = 0; j < shapeCount; ++j)
                    {
                        var points = new List <Vector2>();
                        sprite.GetPhysicsShape(j, points);
                        var collider = new GameObject($"Collider {j}");
                        collider.AddComponent <PolygonCollider2D>().points = points.ToArray();
                        collider.transform.SetParent(gameObject.transform);
                        collider.transform.localPosition = childPosition;
                        collider.transform.localRotation = Quaternion.identity;
                    }
                }
            }
        }