Sprite layer order determined by Y value

I’m working on a top-down sprite-based RPG in Unity and I’ve encountered somewhat of a problem: because of the 3/4 perspective I’m using, sometimes a player should be drawn above an object and other times, below. I’ve achieved this effect in MonoGame by simply sorting sprites by their Y position values and drawing in that order; however, in Unity this doesn’t appear to be possible. Is there any way to achieve this effect?

I ended up placing a function the following code in my update method:

GetComponent<SpriteRenderer>().sortingOrder = Mathf.RoundToInt(transform.position.y * 100f) * -1;

An old question, but now the answer is either to pivot all your sprites to the bottom and then do the global **Edit ** → Project SettingsGraphics → Transparency Sort Mode: Custom Axis + Transparency Sort Axis: X=0, Y=1, Z=0

But I wanted to do it by script:

using UnityEngine;

public enum SortingOrigin
{
    Pivot, Bottom, Top, Left, Right
}
public enum SortingAxis
{
    X, Y
}

[RequireComponent(typeof(Renderer))]
public class LayerSorter : MonoBehaviour {

    [SerializeField]
    private int _originOrder = 100;
    [SerializeField]
    private float _precision = 1f;
    [SerializeField]
    private int _offset = 0;
    [SerializeField]
    private bool _runOnlyOnce = false;
    [SerializeField]
    private SortingOrigin _sortingSelector;
    [SerializeField]
    private SortingAxis _sortingAxis = SortingAxis.Y;

    private Renderer _renderer;
    private float _timeLeft;
    private float _updateFrequency = .1f;

    private void Awake () {
        _renderer = GetComponent<Renderer>();
	}
    private void Start()
    {
        UpdateSortOrder();
        if (_runOnlyOnce)
        {
            enabled = false;
        }
    }

    private void LateUpdate ()
    {
        UpdateSortOrder();
    }

    private void UpdateSortOrder()
    {
        _timeLeft -= Time.deltaTime;
        if (_timeLeft <= 0)
        {
            _timeLeft = _updateFrequency;
            Vector2 pos = _renderer.bounds.center;
            float width = _renderer.bounds.size.x;
            float height = _renderer.bounds.size.y;
            switch (_sortingSelector)
            {
                case SortingOrigin.Bottom:
                    pos += Vector2.down * height / 2;
                    break;
                case SortingOrigin.Top:
                    pos += Vector2.up * height / 2;
                    break;
                case SortingOrigin.Left:
                    pos += Vector2.left * width / 2;
                    break;
                case SortingOrigin.Right:
                    pos += Vector2.right * width / 2;
                    break;
                default:
                    pos = transform.position;
                    break;
            }
            float posFromAxis = _sortingAxis == SortingAxis.X ? pos.x : pos.y;
            _renderer.sortingOrder = (int)(_originOrder - posFromAxis / _precision + _offset);
        }
    }
}

Here’s where I started: Learn game development w/ Unity | Courses & tutorials in game design, VR, AR, & Real-time 3D | Unity Learn

It also has some other good tips on sorting, like sorting groups.

Since this was one of the major results when googling a similar problem, I figure I’d link to my solution based on this answer.

http://forum.unity3d.com/threads/order-in-layer-16-bit-limit-huge-world-in-one-scene.331646/

Order In Layer is 16 bits, so OrderInLayer = Position.Z is limited to 32767,32767.

Unity gives a floating point limitation warning after 99999, which is a little more than 3x the OrderInLayer limitations.

The solution? Divide by 3!

If you change Order In Layer every 3 integers/position instead of every 1, it is really closer to the floating point limitation for positions (32767 * 3 = almost 99999). I tested this by changing Order In Layer every 5, and I didn’t notice any difference in my game. (1 position = 1 pixel). It’s a 3D world with 2D sprites and a perspective camera, so this was not easy after trying so many solutions. I tried other solutions as you can see in the thread (and more that I didn’t mention in the thread.)

Anyway, here is the code:

int pos = Mathf.RoundToInt(theParent.transform.position.z);
pos /= 3;
spriteRenderer.sortingOrder = (pos * -1) + OrderOffset;

As someone is trying to say this is already solved by Unity, but if you are as me and need to have a visual description of the configuration here you are:

Edit > Project Settings > Graphics > Transparency Sort Mode: Custom Axis
Edit > Project Settings > Graphics > Transparency Sort Axis: X=0, Y=1, Z=0

192746-screenshot-2022-02-17-at-170506.png

If you are using Tiles I also recommend to configure:

Tilemap Renderer > Mode > Individual

192747-screenshot-2022-02-17-at-170156.png