What I learned from trying to make an Isometric game in Unity
Published a year ago
12.6 K
Making an isometric game is far from being an easy task, here are a couple of helpful tricks to improve your workflow.
The images used are from the game “A Place for the Unwilling” (by @AlPixelGames), a narrative sandbox set in a victorian city where time is always running and the ending keeps drawing closer. Read more about the game here.
What I learned from trying to make an Isometric game in Unity
I'm the programmer at AlPixel Games. We have been working hard for more than a year on "A Place for the Unwilling", and I thought it would be a cool idea to share part of the technical process we have gone through.
These last few months have been full of challenges that required experimentation and learning by trial and error. Here are some of the lessons I learned along the way.
Unity is an amazing tool for developing games, and since the inclusion of its 2D tools, it has become an even better one. The problem with building 2.5D games, isometric or otherwise, is that we want depth to move objects along 3 axis (x, y, z) while sprites only have 2 (x, y).
When I started looking around forums and blog posts for detailed ways to build an isometric game with 2D sprites in Unity, I couldn’t find a clear, solid method that served my purposes. That’s why I decided to put together this handy little guide to get your Isometric/2.5D project up and running in no time, without the hassle of having to gather all this information yourself.
Let's start by taking a look at the end result:
The first part we are going to focus on is on how to dynamically make sprites move around other sprites (behind and in front of them), giving a sense of real depth. The SpriteRenderer component has 2 properties that allow us to change the rendering order of sprites in the scene.
  • Sorting Layer
  • Order in Layer
To be able to change the rendering order of multiple sprites in real time, we need to modify some values so that when objects move around the scene, they always render correctly. We could modify the “Order in Layer”, but it only accepts integers, and we have a better option. We are going to use the Z axis.
The priority order when rendering a sprite in Unity goes like this, from highest to lowest:
If two sprites share the same “Sorting Layer” and “Order in Layer”, the one closest to the camera (in 3D World coordinates) gets rendered first.
Knowing this, we just have to write a small script that modifies the Z position a fixed amount relative to the Y position, right? You’re close, but first let’s explain a small concept crucial in understanding how to set a sprite’s ground floor. This “floor” is where the sprite would be touching the ground if it were a 3D object. Here are some examples:
What we have to do now is modify the Z position of the sprites when the Y position is modified. Let’s take a look at this in 3D:
With this in mind we can finally write our script:
The first thing we are going to need is the “Floor Height”. This is going to determine the Y height offset from the sprite’s lower bounds. In the 3D world position, it's what sets its Z depth in the scene. If a sprite’s floor is higher than another one, it’s going to be rendered behind it.  
After that we store width/2 and height/2 of the sprite to do some simple math with the Z position.
I used the tangent of 30 degrees because it’s the isometric angle we are using in our game, but you can just set the Z axis to be equal to the Y axis, and it will work just fine.
Two small things. First, the OnDrawGizmos method is being used to draw a line at the current floor height, so that you can set it in the editor to the exact value you want. The other thing to take into consideration is that you are going to have objects that never move once the game is launched. In that case, to make some optimizations, we can use the “if (!Application.isPlaying)” and the”‘#if UNITY_EDITOR” conditions to save calculations in runtime (you may have hundreds of sprites with this script attached simultaneously).
With this setup you can already have stuff moving around and rendering in the correct order depending on its Y position, but there are still two situations where this is not enough.
When dealing with sprites that aren’t centered in the middle, we need to split them. Take this building for instance. Due to the fact that it has a rectangular base, if we just used one floor height for the whole building we could be walking along its front side and be behind it at the same time! To solve this we need to cut the sprite in two, and set a different floor for each slice, like this:
The other case is when we want other sprites as children of another one. Following the building example, let’s imagine that we want to add windows or signs to it. To do that we can’t use the same script we were using with the building, because some windows would be behind it (the ones more at the top). Thankfully, this one is very easy to solve. We just need to make a child object and reset its transform position, but leaving the Z = -0.001. After that just drag and drop all the elements you want to use to decorate your building inside that empty gameobject, and be sure to set their Z = 0, so that they stay 0.001 units separated from the actual building sprite and closer to the camera.
And in case you were wondering, this is how a full scene in 3D looks like:
And that’s it! You already have a pretty flexible toolset to work with, but let’s take a look at some of the limitations of this approach, as well as some extensions and add-ons that will improve our workflow.
Probably the most notorious limitation this approach has is making thin walls. This is because you actually have to split the sprite into multiple slices that have to be the as thin as the wall’s width to allow the other objects of the scene to move around it. Here’s an example:
Flying stuff may give you some headaches as well, but if you are careful with their placement, you should be fine. You can also play around with modifying the Sorting Layer so that they are always in front, or behind, the main objects of the scene.
Finally, I would like to mention some examples of how you could expand this approach and have more versatility.
  • Isometric Colliders: depending on how your characters move in your game, you may want to implement a small script that creates a collider with the exact angles of your art perspective.
  • IsoVector Class: it can be really useful to have a class that contains shortcuts to all the vectors you would generally use (N, W, E, S, NE, NW, SE, SW), as well as methods that allow you to get a vector from a custom direction (and vice versa), or getting the opposite direction to the one given (South -> North), etc.
This has been an interesting learning experience. The first thing I came up with was the script to move the sprites along the Z axis to render everything correctly, that solved the immediate problem of building our world. As I continued expanding the code base, I found myself longing for those other custom classes to facilitate the introduction of new features and, at the same time, be able to maintain a structured project at the same time.
I hope this is useful to someone that is currently developing an isometric game with Unity, and if that’s the case, or you just want to tell me what an awful approach this is, I would love to hear from you!
Feel free to hit me up on twitter (@Tayx94) ;)
Luis Diaz
11 days ago
TomaszHave you tried Shiva ?!/content/ . You dont need to slice sprites and its pixel perfect with additional features(sprite tiling, 3d lighting etc)
11 days ago
Have you tried Shiva ?!/content/ . You dont need to slice sprites and its pixel perfect with additional features(sprite tiling, 3d lighting etc)
Lernie Ang
a month ago
@Aedous I've been up until recently been using Construct 2 doing some RnD for an isometric game I'm developing. I will be jumping to Unity to develop this game to the full, but I wanted to share a novel technique for sorting that hopefully would be of some help. I've explored the some of the principles mentioned in this article using C2, but one the biggest issues I had was sorting the player sprite with an 'irregularly-shaped' sprite. By 'irregular' I also mean thin walls, and sprites that go way beyond the bounds of an isometric tile. The goal of the technique was to find a way to sort regardless of the shape, so I went to Photoshop to work out the logic. :-) I've written a quick article on the principle of this method, though I admit it may lack a few explanations. I was more interested in writing it down as a note than a tutorial.
The principles are this: - The player sprite has a 'sorting collider' which is shaped like a thin bar below the player sprite. - The Y-offset this 'sorting collider' is from the base of the sprite depends on the aesthetics of the sorting result, and the proportions of the isometric tile (ie not all 'isometric' games are 2:1 tiles). - The 'sorting collider's' width should be slightly more than the width of widest animated frame in the sprite (if applicable) - All elements that are meant to be sorted must have a reasonably accurate collision shape representation. - The player sprite is, by default, on top. This can be done every tick if needed (in C2, it is done per tick) - When the player's 'sorting collider' hits any element's collision shape, the player goes behind that element. It's that simple. The link above features some GIFs to illustrate the result. best, lernie.
Мейфу - Other
красиво но не играбельно персонажы - в это не хочетсья играть
4 months ago
Games Programmer - Programmer
AedousNice method of working with Isometric, I'm currently doing the same and using a similar technique with the floor handles you have, however I don't use the Z value :D.
If you ever figure out a way to make things overlap, I would love to hear about it! Been struggling with trying to make it more designer friendly and logical, but so far it's not up to the standards that I would like.