1
\$\begingroup\$

I have been struggling with an issue for a couple of days now trying to get depth sorting properly when using multiple layers in tiled.

My tiled map is set up as follows:

enter image description here

The sorting Layers I have in unity are:

enter image description here

Tiled to Unity sorting layers map as follows:

Background : Level 0

Background Noise : Level 0

Shadows : Level 0

Paths : Level 0

Tree Bases : Level 1

Tree Tops : Level 2

House Bases: Level 1

Objects ( crates and barrels ) : Level 1

House Roofs : Level 2

House Roof Items : Level 3

I have set the player sprite to be on sorting layer 1 along with the tree stumps, walls and floor objects.

When exporting to unity I'm ticking the check box for Use Depth Buffer as below:

enter image description here

Now the problem I am having is that when setting the layer to interact with on the Sprite Depth in map script I can only seem to make one layer work at a time.

enter image description here

eg, if I set it to interact with the tree bases layer, then the depth sorting works on there, but the character appears below the walls and the crates etc, but if I set the layer to interact with the objects layer then the character is always on top of the tree trunks rather than behind.

enter image description here

Interacting with tree layer

enter image description here

Interact with object layer

If I have one layer with the tree trunks, walls and objects (crates, barrels etc) and interact with this layer then it works as expected, but with only one layer in tiled I cant put the barrels in front of the house, or trees behind the house etc.

Is what I'm trying to do even possible with Tiled2Unity? or should I be doing something else?

Any pointers would be appreciated.

\$\endgroup\$
  • \$\begingroup\$ I did not have enough rep to create a tiled2unity tag as there was not one, quite surprised but it might be worth someone creating one. \$\endgroup\$ – WraithNath Feb 25 '18 at 21:26
  • 1
    \$\begingroup\$ I agree a tiled2unity tag would be useful, since there are already many questions related to it. I've added one in an edit, let's see if it makes it through peer review. \$\endgroup\$ – Thorbjørn Lindeijer Feb 28 '18 at 10:02
1
\$\begingroup\$

Ok I have finally managed to come up with a solution for this one, Ill post what I did here as I could not find the information anywhere else online so hopefully it will help someone else in future.

I created a CustomTiledImporter that will look at the sorting layer name on the tiled layer and set the z position of the layer based on the number of layers in the map. This will set all layers that target the same sorting layer to the same value so the map can be created with multiple layers, but they will all share the same sorting layer and z position in unity.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[Tiled2Unity.CustomTiledImporter]
public class WraithNathCustomTiledImporter : Tiled2Unity.ICustomTiledImporter
{

    public void HandleCustomProperties(UnityEngine.GameObject gameObject, IDictionary<string, string> props)
    {
    }

    public void CustomizePrefab(GameObject prefab)
    {
        Tiled2Unity.TiledMap map = prefab.GetComponent<Tiled2Unity.TiledMap>();

        Rect mapRect = map.GetMapRect();
        float depthPerLayer = -map.TileHeight / mapRect.height;

        var renderers = prefab.GetComponentsInChildren<Renderer>();

        foreach (Renderer renderer in renderers)
        {
            //Get the transform for the parent layer
            Transform parentTransform = renderer.transform.parent.transform;
            float z = (depthPerLayer * SortingLayer.GetLayerValueFromID(renderer.sortingLayerID));

            //Set the z position for the layer
            parentTransform.position = new Vector3(parentTransform.position.x, parentTransform.position.y, z); ;
        }
    }
}

I then copied the Tiled2Unity SpriteDepthInMap script and created a new version of it called SpriteDepthInSortingLayer. This is essentially exactly the same but with a property called InteractWithSortingLayer.

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SpriteDepthInSortingLayer : MonoBehaviour {

    [Tooltip("The TiledMap instance our sprite is interacting with.")]
    public Tiled2Unity.TiledMap AttachedMap = null;

    [HideInInspector]
    [Tooltip("Which Sorting layer our sprite is interacting with. Will render above lower layers and below higher layers. Render order of Tiles on same layer will depend on location.")]
    public int InteractWithSortingLayer = 0;

    [Tooltip("For maps where tileset heights are different than map tile heights. Enter the tileset height here. Useful/crucial for isometric maps. Leave at default (0) if you don't care.")]
    public int TilesetHeight = 0;

    private void Start()
    {
        if (this.AttachedMap == null)
        {
            Debug.LogError(String.Format("Sprite must be attached to a TiledMap instance in order to calucluate the 'z-depth' on that map. Check the SpriteDepthInMap component in the Inspector."));
            return;
        }
    }

    private void Update()
    {
        UpdateSpriteDepth();
    }

    public void UpdateSpriteDepth()
    {
        // Put position into map space
        Vector3 spritePosition = this.gameObject.transform.position;
        spritePosition -= this.AttachedMap.gameObject.transform.position;

        // Some maps (like isometric) have a tileset height that is larger than the map tile height in order to get the isometric illusion. We need to know that difference in caluclating depth.
        if (TilesetHeight != 0)
        {
            int delta_y = this.AttachedMap.TileHeight - this.TilesetHeight;
            spritePosition.y += delta_y;
        }

        Rect mapRect = this.AttachedMap.GetMapRect();
        float depthPerLayer = -this.AttachedMap.TileHeight / mapRect.height;

        float depth_z = (spritePosition.y / this.AttachedMap.ExportScale / mapRect.height) + (depthPerLayer * this.InteractWithSortingLayer);

        // Assign our depth value in the z component.
        this.gameObject.transform.position = new Vector3(this.gameObject.transform.position.x, this.gameObject.transform.position.y, depth_z);
    }

}

You don't need to create the new script above as the old one will work, just remember you are now referencing a sorting layer rather than a map layer. I just wanted to make a new script so I could create a better editor for it as per below;

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System;
using System.Reflection;

[CustomEditor(typeof(SpriteDepthInSortingLayer))]
public class SpriteDepthInSortingLayerEditor : UnityEditor.Editor
{

    public override void OnInspectorGUI()
    {
        DrawDefaultInspector();

        // Get the renderer from the target object
        var script = (target as SpriteDepthInSortingLayer);

        // If there is no script we cant do 
        if (script==null)
            return;

        //Get the current sort layer selection
        int sortLayerSelection = script.InteractWithSortingLayer;

        GUIContent[] sortingLayerContexts = GetSortingLayerContexts();
        int newSortingLayerIndex = EditorGUILayout.Popup(new GUIContent("Sorting Layer"), sortLayerSelection, sortingLayerContexts);

        //Change layer or show layers menu
        if (newSortingLayerIndex == sortingLayerContexts.Length - 1)
        {
            EditorApplication.ExecuteMenuItem("Edit/Project Settings/Tags and Layers");
        }
        else if (newSortingLayerIndex != sortLayerSelection)
        {
            Undo.RecordObject(script, "Edit Sorting Layer ID");
            script.InteractWithSortingLayer = newSortingLayerIndex;
            EditorUtility.SetDirty(script);
        }

        //Add button to set the depth now
        if (GUILayout.Button("Set Depth (Changes Transform Z Position)"))
        {
            if (script.AttachedMap == null)
            {
                Debug.LogError("Cannot set sprite depth without an Attached Map");
            }
            else
            {
                script.UpdateSpriteDepth();
            }
        }
    }

    public static string[] GetSortingLayerNames()
    {
        Type internalEditorUtilityType = typeof(UnityEditorInternal.InternalEditorUtility);
        PropertyInfo sortingLayersProperty = internalEditorUtilityType.GetProperty("sortingLayerNames", BindingFlags.Static | BindingFlags.NonPublic);
        return (string[])sortingLayersProperty.GetValue(null, new object[0]);
    }

    public static GUIContent[] GetSortingLayerContexts()
    {
        List<GUIContent> contexts = new List<GUIContent>();

        foreach (string layerName in GetSortingLayerNames())
        {
            contexts.Add(new GUIContent(layerName));
        }

        contexts.Add(GUIContent.none);
        contexts.Add(new GUIContent("Edit Layers..."));

        return contexts.ToArray();
    }
}

enter image description here

Now the character can go in front and behind of any sprite I put on sorting layer level 1 (or different if selected in the editor) regardless of which map level they are on.

Note: Its Important to still export the Tiled map into unity with the Use Depth buffer option ticked as this uses a depth shader on the layers.

Note 2: I also set the order in layer of my player sprite to 999 so it was on top of everything else, I added some more layers to the map later and it started appearing behind sprites with higher order in layers. Works perfectly now.

\$\endgroup\$
-1
\$\begingroup\$

mine works nothing at all no matter what setting I use I am pretty sure the version of tiled I use has a broken script

but how do you run your own version of scripts ?

(sorry I cant comment becos of insufficient reputation please move this into the comment section instead of voting me down in such a childish manner)

\$\endgroup\$
  • \$\begingroup\$ You need to drop the custom tile importer script into the tiled folder in the unity folder, I think it goes in the runtime scripts folder. Then when you use the tiled2unity program it finds the script and runs it. Then you just need to attach the sprite depth in sorting later srcipt to your sprites (btw It was not me that downvoted) \$\endgroup\$ – WraithNath Mar 12 '18 at 9:36
  • \$\begingroup\$ I was guessing the admin downvoted my post :-) I hate these things although I understand it's necessary \$\endgroup\$ – fdsfdsfdsfds Mar 12 '18 at 15:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.