Character sprite rendering order

I have a character made of multiple sprites so I can change a specific sprite. For example, I can make sprite sheet of shirts and change the “shirt”-sprite to change character’s shirt.

Sprites rendering order has to be reasonable (hat is on upper layer than head etc). This can be done in several ways, but the problems come when character interferes with another character.

What I want:

  • Characters that have smaller y-position always to be rendered first.
  • Character body parts to be rendered in specific order, but this shouldn’t break the previous rule.
  • All this should work with x-amount of moving characters.

Here’s what I’ve tried so far:

  1. Use sprites “order in layer”-system for all character sprites. Then I change character’s z-value depending on y-position. Works with one character but when character interferes with other, higher layer sprites will always be rendered first, no matter what the z-value is.

  2. Use only the z-position for rendering the character different parts (sprite layers is set to 0). I Change parts z-value (first rendered parts to smaller values), but I use really small differences (last rendered sprite z is 0, second -0.0001 etc). I also change the character’s main z-value depending on y-position. All seems to work fine in editor, but when I press play, sprites start to flickering randomly. This won’t happen if I use higher differences for parts z-value, but when two character y-values are close to each other, sprites that has smaller z will always be rendered first.

I think Unity SpriteRenderer should have sublayers.

You could try putting the player’s character on a higher sorting layer than the NPCs or enemies. Then you can still have ordered sprites within your player, and still control how they overall stack in the game.

Example

  1. Create two new sorting layers under edit layers (player and NPCs)
  2. On your player prefab, set the sprite renderers to the player sorting layer.
  3. Change the order of the sprites in the player using the order in layer on the sprite renderers
  4. Do the same for the other characters (in this example NPCs) except use the NPCs sorting layer

Well that depends on how many characters you have in scene?

If number of characters are static and less(e.g. 3) than you can define new Layer in ‘Sorting layers’ in project settings->tags and layers.

If number of characters are dynamic then I think you have to fill ‘order in layer’ value from script as per character movements.

Let me know if you need detailed explanation with your requirement.

I was sorely disappointed with the answers. I’m not sure if this will work for everyone, but it works for me.

Here is how you do it. It was actually easier than I thought, but it took time for it to click and for me to get that lightbulb moment.

What you want to do, is have one script which takes all of the Sprites, and adjusts their OrderInLayer based on their Transform (in my example, Transform.position.Z, but in 2D games it would be Transform.position.Y), but keeping the original sorting order of each piece of the character.

So what you do, is simple math:

OrderInLayer = Transform.Position.Y;
Then simply add the original offset OrderInLayer.

It’s as simple as during Start() of the script, grab the original layer using:
OriginalLayer = CharacterPartGameObject.GetComponent().sortingOrder;

Then during update, simply apply the math:

CharacterPartGameObject.GetComponent().sortingOrder = (transform.position.z + HeadLayer) * -1;

Here is a script which takes my character, who is comprised of a Head, Torso, and two parts for his arms/legs.

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

public class CharacterOrderInLayer : MonoBehaviour
{
	//GameObject LimbPart, is the gameobject with the SpriteRenderer (the gameobject which has the Sprite).
	//int LimbLayer, is the original OrderInLayer of the sprite. This is what you want to keep, relative to all other limbs.
	//Link all of the gameobjects in the inspector, or you could theoretically use a GetComponentsInChildren method to grab by tag or name or whatever automatically.

	//Character's Head Sprite
	public GameObject HeadPart;
	int HeadLayer;

	//Character's Torso Sprite
	public GameObject TorsoPart;
	int TorsoLayer;

	//Character's Right Arm
	public GameObject RightForeArmPart;
	int RightForeArmLayer;
	public GameObject RightBicepPart;
	int RightBicepLayer;

	//Character's Left Arm
	public GameObject LeftForeArmPart;
	int LeftForeArmLayer;
	public GameObject LeftBicepPart;
	int LeftBicepLayer;

	//Character's Right Leg
	public GameObject RightThighPart;
	int RightThighLayer;
	public GameObject RightShinPart;
	int RightShinLayer;

	//Character's Left Leg
	public GameObject LeftThighPart;
	int LeftThighLayer;
	public GameObject LeftShinPart;
	int LeftShinLayer;

	void Start()
	{
		HeadLayer = HeadPart.GetComponent<SpriteRenderer>().sortingOrder;	
		TorsoLayer = TorsoPart.GetComponent<SpriteRenderer>().sortingOrder;	
		RightForeArmLayer = RightForeArmPart.GetComponent<SpriteRenderer>().sortingOrder;	
		RightBicepLayer = RightBicepPart.GetComponent<SpriteRenderer>().sortingOrder;	
		LeftForeArmLayer = LeftForeArmPart.GetComponent<SpriteRenderer>().sortingOrder;	
		LeftBicepLayer = LeftBicepPart.GetComponent<SpriteRenderer>().sortingOrder;	
		RightThighLayer = RightThighPart.GetComponent<SpriteRenderer>().sortingOrder;	
		RightShinLayer = RightShinPart.GetComponent<SpriteRenderer>().sortingOrder;	
		LeftThighLayer = LeftThighPart.GetComponent<SpriteRenderer>().sortingOrder;	
		LeftShinLayer = LeftShinPart.GetComponent<SpriteRenderer>().sortingOrder;	
	}
	
	// Update is called once per frame
	void Update ()
	{
		int Zlayer = Mathf.RoundToInt(transform.position.z); //Turn the gameobject's Z position into an integer, so it can be converted to the layer.  (TLDR:  Transform.Position.Z = SortingOrder). Change this from Z to Y if you are using Unity2D.
		Zlayer -= 90; //Custom Offset, because my sprite is +90z when at position (0x,0y,0z). This is NOT required.

		//Each of these takes the individual sprites which make up the character, and then sets the correct SortingOrder based on their Transform.Position, while keeping all of the sprite's relative positioning.
		HeadPart.GetComponent<SpriteRenderer>().sortingOrder = (Zlayer - HeadLayer) * -1;	
		TorsoPart.GetComponent<SpriteRenderer>().sortingOrder = (Zlayer - TorsoLayer) * -1;	
		RightForeArmPart.GetComponent<SpriteRenderer>().sortingOrder = (Zlayer - RightForeArmLayer) * -1;	
		RightBicepPart.GetComponent<SpriteRenderer>().sortingOrder = (Zlayer - RightBicepLayer) * -1;	
		LeftForeArmPart.GetComponent<SpriteRenderer>().sortingOrder = (Zlayer - LeftForeArmLayer) * -1;	
		LeftBicepPart.GetComponent<SpriteRenderer>().sortingOrder = (Zlayer - LeftBicepLayer) * -1;	
		RightThighPart.GetComponent<SpriteRenderer>().sortingOrder = (Zlayer - RightThighLayer) * -1;	
		RightShinPart.GetComponent<SpriteRenderer>().sortingOrder = (Zlayer - RightShinLayer) * -1;	
		LeftThighPart.GetComponent<SpriteRenderer>().sortingOrder = (Zlayer - LeftThighLayer) * -1;	
		LeftShinPart.GetComponent<SpriteRenderer>().sortingOrder = (Zlayer - LeftShinLayer) * -1;	
	}
}

Thanks for your answers

I solved this partially by writing a method that changes all the ‘order in layers’ of the character’s sprites depending on the y-position of the character.
The method triggers only if there’s a change in the character’s y-position.

I changed the character’s ‘local’ sprite order by adjusting sprites’ position z-values with numbers large enough. I think Unity should include some kind of a sublayer-system here.

However, if there are different sized objects, in which layers also need to be updated, you’ll have to consider the point of sprite where you start calculating the right layer.
Usually you’ll want to start calculating from the bottom of the sprite. So basically you compare sprites’ bottom point of the y-position and render the lower first.