Hello Guest

Author Topic: [How To] Mix sprites and other 3D elements in your 2D game without sorting issue  (Read 13252 times)

TekuStudios

  • 2D Toolkit
  • Full Member
  • *
  • Posts: 177
    • View Profile
    • Teku Studios
Hi there! We're posting here a workaround for the new Unity layer-and-sorting system, just in case you need something similar for your games. We are developing a sidescrolling tk2dSprite-based game, but we also have some 3D elements in our scenes such us particle effects and dynamically generated meshes (faked 2D planes with deformation physics simulating water), and we are using a Perspective camera as well. This made us face a very uncomfortable problem: all our sprites were being rendered in front of every other non-sprite elements in the scenes. The new Layer and SortingOrder properties are public yet only exposed in the Editor for the new Unity sprites (or tk2d ones).

So, as some of you may be facing similar trouble, I'm sharing our solution with you. We use a modified version for the Mesh Renderer that allows you to set the Layer Name and Sorting Order for every mesh-based GameObjects:

Code: [Select]
using UnityEngine;
using UnityEditor;
using System.Collections;

[CustomEditor(typeof(MeshRenderer))]

public class MeshRendererSortingLayersEditor : Editor
{
public override void OnInspectorGUI()
{
base.OnInspectorGUI();

MeshRenderer renderer = target as MeshRenderer;

EditorGUILayout.BeginHorizontal();

EditorGUI.BeginChangeCheck();

string name = EditorGUILayout.TextField("Sorting Layer Name", renderer.sortingLayerName);

if(EditorGUI.EndChangeCheck())
{
renderer.sortingLayerName = name;
}

EditorGUILayout.EndHorizontal();

EditorGUILayout.BeginHorizontal();

EditorGUI.BeginChangeCheck();

int order = EditorGUILayout.IntField("Sorting Order", renderer.sortingOrder);

if(EditorGUI.EndChangeCheck())
{
renderer.sortingOrder = order;
}

EditorGUILayout.EndHorizontal();
}
}

You just have to create a new C# script, paste that code into it and place it inside the Editor folder of your project so everytime you add the Mesh Renderer component to an object it will allow you to set its layer and rendering priority. Unfortunately, you have to set the Layer as a string name, so make sure you don't throw any typos in that field.

Hope you guys find it useful!
« Last Edit: March 26, 2014, 09:46:33 am by TekuStudios »
We are an Indie videogame developer located in Teruel, Spain. A small 6-people team which is currently working on the upcoming 'Candle'.

vinnie035

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 20
    • View Profile
Thanks guys for sharing this script.

Here is an improved version.

Code: [Select]
using System;
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using System.Reflection;

[CanEditMultipleObjects()]
[CustomEditor(typeof(MeshRenderer))]
public class MeshRendererSortingLayersEditor : Editor
{
    Renderer renderer;
    string[] sortingLayerNames;
    int selectedOption;

    void OnEnable()
    {
        sortingLayerNames = GetSortingLayerNames();
        renderer = (target as Renderer).gameObject.renderer;

        for (int i = 0; i<sortingLayerNames.Length;i++)
        {
            if (sortingLayerNames[i] == renderer.sortingLayerName)
                selectedOption = i;
        }
    }

    public override void OnInspectorGUI()
    {
        DrawDefaultInspector();

if (!renderer) return;

EditorGUILayout.BeginHorizontal();
        selectedOption = EditorGUILayout.Popup("Sorting Layer", selectedOption, sortingLayerNames);
        if (sortingLayerNames[selectedOption] != renderer.sortingLayerName)
        {
            Undo.RecordObject(renderer, "Sorting Layer");
renderer.sortingLayerName = sortingLayerNames[selectedOption];
            EditorUtility.SetDirty(renderer);
        }
  EditorGUILayout.LabelField("(Id:" + renderer.sortingLayerID.ToString() + ")", GUILayout.MaxWidth(40));
EditorGUILayout.EndHorizontal();

        int newSortingLayerOrder = EditorGUILayout.IntField("Order in Layer", renderer.sortingOrder);
        if (newSortingLayerOrder != renderer.sortingOrder)
        {
            Undo.RecordObject(renderer, "Edit Sorting Order");
            renderer.sortingOrder = newSortingLayerOrder;
            EditorUtility.SetDirty(renderer);
        }
    }

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

TekuStudios

  • 2D Toolkit
  • Full Member
  • *
  • Posts: 177
    • View Profile
    • Teku Studios
I completely overlooked your answer, vinnie. Thanks a lot for sharing!
We are an Indie videogame developer located in Teruel, Spain. A small 6-people team which is currently working on the upcoming 'Candle'.