I discovered a nice simple trick on how to dynamically change the depth of a sprite for top down 2D games. For this project, I used this asset and the character comes from here.
Imagine you have your player character roaming around the game. If you simply place the sprites in the scene, they should automatically be set to the same Sorting Layer, and therefore, this should happen:
There is no depth whatsoever, the player is constantly drawn behind the trees, which is fine when he is walking "behind" them, but it looks just wrong when he is in front of them.
Of course, changing the player's sorting layer won't make any difference:
I therefore had to write a very simple script which allows the sprites to dynamically change their sorting layer according to their position.
This is DynamicSortingLayer script:
Of course, changing the player's sorting layer won't make any difference:
I therefore had to write a very simple script which allows the sprites to dynamically change their sorting layer according to their position.
This is DynamicSortingLayer script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | public class DynamicSortingLayer : MonoBehaviour { public float yOffset; public float by; float layer; SpriteRenderer rend; Vector3 centerBottom; // Use this for initialization void Start () { rend = GetComponent<SpriteRenderer> (); } void Update () { centerBottom = transform.TransformPoint(rend.sprite.bounds.min); layer = centerBottom.y + yOffset; rend.sortingOrder = -(int)(layer * 100); } } |
The sorting layer is assigned depending on the position of the sprite, however, when we get the position of the object we usually get its anchor position, which is normally its center. In this case, we want to get the position of the bottom of a sprite. For example, for our player, we want to assign the layer according to its feet Y position, because that's the point which determines whether he is in front or behind the trees.
That's what we do on line 22, we get the bottom-centre points of the sprite and store it into centerBottom. After adding an offset value to it (for minor adjustments), we multiply the Y value position for 100, in order to preserve decimal numbers as we are going to cast it as an int value. Of course, we also need to negate the final value, as we want the sprite at the lowest part of the screen (with lower Y value) to be in front of the other ones and they therefore need a higher value of sorting layer.
This is the final result:
Conclusion
A very quick tutorial on how to create depth in a 2D world. To optimize the script you could separate moving objects from static ones. For, example, the trees do not need the get the sorting layer constantly reassigned as they are not moving. You could assign the sorting layer once in the Start method and leave the Update empty. The player, however, will need to continuously change its sorting layer to ensure it will be drawn correctly in the scene. I placed some colliders onto our objects and put together a simple scene which you can try the WebGL version here.
what is the "by" float for?
ReplyDeleteWell spotted,I frankly cannot remember but I believe that was something I was experimenting with, didn't need it and forgot to delete it :)
DeleteHowever, I would say that this post might be obsolete now. Unity has introduced better techniques to sort objects by different axis,
Have a look at this:
https://unity3d.com/learn/tutorials/topics/2d-game-creation/sorting-groups-and-transparency-sort-axis?playlist=17093