Here are two small tricks that can help if you're making an isometric 2D game in Unity. Ok, so not actually isometric, but that's the term we're used to in videogames, so we'll go with it. These are quite basic and if you're working on such a game you've probably already tackled them your own way. This is our take on it, hopefully it's useful to someone.

Sprite Ordering

Normally in a 2D game there is no concept of depth, so if you simply place the sprites in the world, you'll most likely have objects appearing in the wrong order than what you'd expect in an isometric game.

Thankfully Unity exposes Sorting Layer and Order In Layer properties for Renderers.

A quick fix is to set the value of Order in Layer to depend on the Y position of the object.

[ExecuteInEditMode] [RequireComponent(typeof(Renderer))] public class DepthSortByY : MonoBehaviour { private const int IsometricRangePerYUnit = 100; void Update() { Renderer renderer = GetComponent(); renderer.sortingOrder = -(int)(transform.position.y * IsometricRangePerYUnit); } }

This solves the problem for the simplest case, when we assume all objects rest on the ground.

Let's assume we want to have an object that is above the ground in the world, like placing a bird house on that tree. Just trying to place it in the world will treat the pivot of the object as being at ground level, with no way to both place it at a proper height and sort it correctly.

There are several options for this. Just to get it out of the system, the first option is to add empty space to the texture below the bird house to make sure the pivot is at ground level (in Unity, the pivot can't be outside of the sprite). This is baaaad! This is wasting texture space, and all instances of that object will need to be at the same height in the game. There are other, less insane, options.

One is having a height property in the DepthSortByY behavior and subtract it from transform.position.y when computing the sorting order.

Another solution (which we went with) is allowing the DepthSortByY behavior to make the depth computation based on another object's transform. This way, the objects will be considered to be at the same point in space as their target and they'll have the same depth order, even if they're at different Y positions in the scene. In the bird house example, the bird house uses the tree's world position for its depth computations.

This solution works better for our game, because it allows artists to move the item freely while staying at the depth (and not have to deal with editing the "height" parameter). And mainly because all the gameplay takes place in the ground's 2D plane anyway so all objects are guaranteed to have a root object that has the ground position. In your own game, it might be easier to just use the first option.

[ExecuteInEditMode] [RequireComponent(typeof(Renderer))] public class IsometricObject : MonoBehaviour { private const int IsometricRangePerYUnit = 100; [Tooltip("Will use this object to compute z-order")] public Transform Target; [Tooltip("Use this to offset the object slightly in front or behind the Target object")] public int TargetOffset = 0; void Update() { if (Target == null) Target = transform; Renderer renderer = GetComponent(); renderer.sortingOrder = -(int)(Target.position.y * IsometricRangePerYUnit) + TargetOffset; } }

This is how this example is set up in Unity:

And this is how it behaves in practice:

Ground Projection

For certain visual elements and effect, we wanted them to look properly projected on the ground, but also not spend too much time on making art for them. The 'isometric' view of the game means that anything that is horizontally on the ground should look squashed vertically.

For simple sprites, this is quite easy. Just draw them directly with the correct perspective and place them in the game.

Things get more complicated when you need something that should be able to rotate in any direction. Like something to show the direction the character is moving in, or some visual effect sweeping the ground towards your attacking direction. Especially if these are things that are animated, drawing them manually for all possible orientations is out of the question (or so the artists claim).

Our solution is: the artists draw and animate these effects as if viewed top-down, and the programmers take care of transforming them at runtime to look as if they were projected on the ground. Without any transformation