- Home /
How to calculate sorting order around diagonal objects
I'm making a 2D isometric game, orthographic camera. To control the layering, I set the sorting layer order based on the Y-coordinate of each object in the environment (set only in the editor, not at runtime), so that lower objects on screen appear in front of higher objects. My character then changes order in layer on the fly to appear in front/behind objects. Pretty simple system and it works well.
The problem I'm running into is that when an object in the environment is diagonal (which is pretty common in isometric view), my character may technically have a higher Y-coordinate than that object, but is actually still supposed to be in front of it. For example, imagine a fence at a 45-degree angle with a pivot point set to the bottom center of the fence. If you want your character to walk along the front side of the fence, as soon as they get past the middle of the fence where the pivot point is, the character will switch to being layered BEHIND the fence, even though the character is still in front of it but they just happen to be higher than the pivot point. Example:
In this example I have the character's pivot point at the bottom of her feet, and the concrete barrier's pivot point at the bottom center, so in the left image the character's pivot point has gone below the concrete barrier's pivot point and thus is rendering in front of it. Yet at that position I still want the character rendering behind the barrier. In cases like this, the same Y-coordinate on the left side of the barrier needs to render a different order than on the right side of the barrier, but I can't think of a way to do that.
Does anyone know a solution to this problem? I'm a hair's breadth from adding trigger colliders to every object so I can detect when my character is near it and move the object up/down sorting layers to force the layering, but that requires far more processing and would not work with multiple characters in the scene.
I originally assumed I would be building the game with a perspective camera, so this wouldn't be an issue, but I don't understand how I would get 2D sprites to line up if they were different distances from the camera, since further objects are smaller. I like keeping everything flat 2D, it's just this one ordering issue that I'm hung up on.
I suspect you dont uses a grid system? I think it will be very difficult to sort the sorting out if you don't use one. Check out this tutorial http://bigspritegames.com/isometric-tile-based-game-part-1/ it is for xcode but the principals are the same.
Answer by sn1ckers · Feb 01, 2016 at 11:20 PM
I just uses this in the update function imageRenderer.sortingOrder = POS.x * POS.y * - constant
on moving objects and it works well. And all the other object are sorted with the same formula but not in update if it is static objects. I use the constant if I need a deeper sorting on the character for example, if you have 5 body parts that's also needs to be sorted in that game object I will use 5 as a constant.
It is explained more here 33min in https://www.youtube.com/watch?v=HM17mAmLd7k
Can you elaborate exactly what you're doing with POS.x and POS.y? I'm not quite following.
I updated my post, and it also needs to be in the same sortingLayer to work becouse sorting order only works in the same layer.
I'm still not seeing how this solves my specific problem. I added an image to my original post (and a bit more explanation) to illustrate the problem. I've got sorting set up exactly how they show it in that video you linked to. It works fine except in cases of thin diagonal objects like in my image.
I looked into using POS.x * POS.y but I don't understand how to make that work because those numbers can be either positive or negative and I end up with wildly inaccurate calculations where for example the X is positive but the Y is negative
Answer by Asofi · Jun 26, 2018 at 05:00 PM
Hey, @theredace, just wanna to ask, have you solved this problem? I have the same now(
Yeah, I ended up doing it with math. Basically using the equation of a 2D line: y = mx + c.
"m" is the slope of the line. For a 45-degree angle line, "m" is either 1 or -1 depending on the direction the object is facing. Art is typically not drawn perfectly isometric, it's actually at a lower angle, so to get my equation right for my particular art I had to use 0.57f or -0.57f. If the side of the object you see is the right side, then you use the positive number, or if you see the left side then you use the negative number. I set the direction as an enum on each object, either Left or Right, so I know what to use in the equation when layering with that particular object.
"c" is the Y-intercept along that line. You can flip the equation around to c = y - mx to solve for this. You get c = objectYposition - (m * objectXposition). You can do this for any point along the line, so presumably just the object's position if the pivot point is placed centered somewhere along that line.
"x" is the character's x position.
So now we can solve for y in our original equation:
y = (m characterXposition) + (objectYposition - (m objectXposition)).
Again, the value of "m" depends on the direction the object is facing, and the particular value you work out depending on the angle your art is drawn at.
So that gives us the Y-intercept along that line at the character's current position. We can then have some branches to figure out the layering by comparing the character's X position to the obstacle's X position, and comparing the character's Y position to the Y-intercept that we just calculated. We have to know both in order to deter$$anonymous$$e where the character should layer. There are basically 4 possibilities, something like:
if (m < 0)
{
if (charPosition.x <= obstaclePosition.x && charPosition.y < y-intercept)
//set character layered in front of object
else if (charPosition.x > obstaclePosition.x && charPosition.y > y-intercept)
//set character layered behind object
}
else
{
if (charPosition.x >= obstaclePosition.x && charPosition.y < y-intercept
//set character layered behind object
else if (charPosition.x < obstaclePosition.x && charPosition.y > y-intercept
//set character layer in front of object
}
I put a trigger collider on the object and trigger this to code to loop on the character while it's inside that collider (while it's close to the object). So it just keeps resetting as it moves around close to the object. I do have some other stuff going on to get the sorting just right, but this is the general gist of how it works. I know it's a bit confusing, hopefully it makes sense.
@theredace Thanks for this, it really helped me figure out what to do. That said, parts of your nested if code seem like they aren't necessary and/or might make the function not work in some cases. Here's my code:
float yIntercept = (slope * character.x) + (object.y - (slope * object.x));
if(character.y < yIntercept)
return true; //Character is above object
return false; //Character is below object
You don't need to check the slope or charPosition.x against obstaclePosition.x because those values are already factored into the equation. All you need to do is check the character's position against the yIntercept. For cases that might not work, what would happen if slope < 0, charPosition.x <= obstaclePosition.x and charPosition.y > y-intercept? Again, thanks for the help, I'm just kinda curious why you coded it the way you did
Your answer
Follow this Question
Related Questions
Pan an isometric ortho camera 2 Answers
Ortho-Isometric camera not playing nice with culling 1 Answer
How to sort sprites in a 2d isometric game 0 Answers
Moving a Rotated Camera 0 Answers
Tilemap sorting of individual tiles 0 Answers