Search Unity

Isometric z as y tilemap sorting issues

Discussion in '2D' started by Ziamor, May 13, 2019.

  1. Ziamor

    Ziamor

    Joined:
    Nov 10, 2014
    Posts:
    2
    I'm trying to get my player character to correctly sort, but there are points on the ground where it will render the ground on top of the player. I have set the custom sort axis to (0,1,-0.26) and set the players z position to 1 and added sorting group.

     

    Attached Files:

  2. ChuanXin

    ChuanXin

    Unity Technologies

    Joined:
    Apr 7, 2015
    Posts:
    1,068
    I assume the ground is made up of Tiles in a Tilemap? It looks like these Tiles have their Sprites with the pivots set to the center, could you try setting it up at the bottom center instead?
     
  3. Ziamor

    Ziamor

    Joined:
    Nov 10, 2014
    Posts:
    2
    I gave that a shot and it made things even worse. I had the pivots before at 50% and 25% for both the tiles and the player. I changed it to Bottom Center for the tiles and the problem was still there, and then I made the player also Bottom Center and still having issues. I'm not sure if this is the proper way, but I have the player Z pos at 1, increasing it more does help but then it causes problems with walls at the same level as the player.
     
  4. dmariaa

    dmariaa

    Joined:
    Dec 7, 2016
    Posts:
    3
    I am having exactly the same problem, same parameters. Unity 2019.1.3f1.
     
  5. dmariaa

    dmariaa

    Joined:
    Dec 7, 2016
    Posts:
    3
    Hi! Have you got to solve this problem? I am still fighting it, not sure about the best workflow to make it work..

    Kind regards

    David
     
  6. Spriterman21

    Spriterman21

    Joined:
    Mar 6, 2020
    Posts:
    5
    Playing around with the z value of the transparency axis (Edit->ProjectSettings->Graphics) somewhat helps to reduce this glitch, however it can also cause some issues witch your tilemap rendering. Some positive effect can have changing z position of your player character, but again it does not solve the issue.

    If someone knows a way to get rid of this problem completely please let us know.
     
    FatemaSH likes this.
  7. Lo-renzo

    Lo-renzo

    Joined:
    Apr 8, 2018
    Posts:
    1,514
    The blue wall should be on a different tilemap with its renderer's mode set to Individual. It should also have its layer or order-in-layer set higher than the floor, so it always renders above the floor. For the custom transparency sort axis, you may need to play around with the #s. It may depend upon how much z you grant between the different z-levels (as set in the Grid component's cell size).
     
    Last edited: Apr 9, 2020
  8. Spriterman21

    Spriterman21

    Joined:
    Mar 6, 2020
    Posts:
    5
    I don't think you can set the order in layer higher than the floor, because you might want the player (blue box) to render sometimes behind the floor, when you want to use the z as y tilemap for elevation. Creating a tilemap for the player might be of some use, although I don't see how. I personaly would prefer my characters to stay as normal sprites, as those are much easier to handle.
     
  9. Derekloffin

    Derekloffin

    Joined:
    Mar 14, 2018
    Posts:
    322
    I've had this same issue myself. For my game I have the player Z set to 3. 1 is only a 1/2 tile in height so it definitely won't do it, so in theory you should actually be using 2, but I found that was still causing issues so went with 3, although that was before I fixed my character graphic (was completely incorrect scaling and unit size) so 2 might work properly now. 4 is definitely too much as it will peak through blocks it definitely isn't supposed to.
     
  10. Derekloffin

    Derekloffin

    Joined:
    Mar 14, 2018
    Posts:
    322
    So, more to my last. Since this topic was brought up, I messed with my own project a bunch and think I got an idea what is going wrong, and how to fix it.
    First, yes, you should be set to 2, not 1 Z (3 was broken in other ways). 1 Z is just half a tile and still doesn't work right. Next, you need to ensure whatever sorting point you set, that your player graphic never crosses below that. So Pivot sorting on the center bottom initially looked promising except when I switched the pivot it also switches where the sprite is rendered, and for some strange reason still seems to sort where the bottom of the sprite object is, even though that is nowhere near the actual sprite bottom (at least for me), it is actually far lower, causing the sorting to have too much priority. There may be a way to fix that (honestly I'm puzzled why it works this way at all for me), but I'm thinking the graphic itself may be the issue, that it has to be in the upper half of it's 'cell' as it were and you just use center sorting. Since most character graphics are centered that will cause them to clip inappropriately if they are center sorted, but if you confine the character to the upper half, they should never enter the overlapping region to have this issue.

    Really makes me think they need a better way to specify the sorting point.
     
  11. Spriterman21

    Spriterman21

    Joined:
    Mar 6, 2020
    Posts:
    5
    For me changing the pivot point has pretty much the same effect as changing the player's Z position. Seting the pivot point higher and Z to a larger number yelds completely same results as having pivot lover and Z lower. Although it can solve the issue of "clipping" through floor, it also completely breaks the 3Dish effect of walking behind a tile, which serves as a wall or elevation, as you will simply render on top of it, not behind

    Either you have this problem
    upload_2020-4-16_13-28-1.png

    or this problem
    upload_2020-4-16_13-29-1.png

    You can find somewhat balance between these, but can't solve them completely.
     
  12. Derekloffin

    Derekloffin

    Joined:
    Mar 14, 2018
    Posts:
    322
    At this point I'm of the belief that the pivot option isn't working as described. I've fiddled with it for quite a while and it is consistently sorting far lower than the actual pivot point, to the point it will even override tiles far in front of it. My best guess is it is sorting a full unit below the actual pivot point of the sprite, causing it to have effectively 2 higher Z, but not completely. For example, if I go to a left or right corner it doesn't sort behind like it should, but if I go to a rear corner it mostly does which makes no sense as it is inconsistent, although maybe it is as I was able to get it to peek through right near the edge of the tile.

    Center sorting seems to work consistently, but I'm not sure it is either. Assuming it is, the solution would be to change the player sprite to be in the upper half of the sprite instead of the usual center. Clumsy, but it should theoretically work. Without further testing though, I'm no longer confident it will.
     
  13. Derekloffin

    Derekloffin

    Joined:
    Mar 14, 2018
    Posts:
    322
    Further testing and lots of failure and I think I know what the problem is, but I can only guess at a solution.
    The problem seems to be that sorting is purely Y coordinate based, ignoring the X entirely so no matter how you shift things, at various X's it won't work since the isometric grid actually changes sorting based in X.

    So then, the potential solution would be to dynamically alter your sorting as X coordinate changes. Either change the pivot or change the Z to simulate a lower or higher sort. Exactly what formulation you'd use, I don't know and I am highly suspicious that you'll still run into sorting issues around the corners as I don't think there is any correct sort at the joining point of a lower tile to an upper tile and you're character behind the upper tile. It seems to either sort in front of both (so lower is correct and upper is wrong) or behind both (so lower is wrong and upper is correct). I'm going to fiddle with some testing later but I'm not optimistic.

    So this actually is making me think of regressing to my really old idea of overlaying fake tiles which are sprite gameobjects around the player with the correct sorting.and scrapping use of the tilemap sorting of mobile objects entirely. Problem with this solution is it is gameobject intensive, and can become very complicated when considering multiple mobile entities. It will work, as you have complete control over sorting now, but I dread the kind of logic needed to make it work and still maintain performance once you have a fair number of mobiles in your view area. Sadly, at this moment, it might be the only way to truly get it right.
     
  14. Spriterman21

    Spriterman21

    Joined:
    Mar 6, 2020
    Posts:
    5
    Changing sorting dynamically is pretty much what I do now, it's not perfect, not easy and requires quite an extensive amount of manual work but it's working. When I set the values correctly, i didn't even have to change it when moving on the same height level in my tilemap, as my game only requeires grid based movement so I don't get much of the "corner texture glitching". The only bigger problem is when I want to go uphill or downhill. I managed to solve this by changing the z position of my object via animation, which is the most labor intensive part, but it's somewhat working.

    The idea with more gameobjects instead of tiles is interesting and might be seriously usefull. I was thinking about using multiple isometric tilemaps instead of one z as y, but that could get complicated as well. I think you could use a tilemap with some prefab brush (just heard about those, don't know much how they work) to paste in tiles as separate gameobjects but still organized in a tilemap. Again, I don't know much about prefab brushes in tilemaps and I did't try any of this. It's just an idea.
     
  15. Derekloffin

    Derekloffin

    Joined:
    Mar 14, 2018
    Posts:
    322
    Well, it's been a while but I finally think I came up with a solution, which is surprisingly simple, although a bit devious.

    Okay, as I noted before, the problem is the sorting algorithm only takes into account the Y, and completely ignores the X. That works fine for the tiles as they are always in the same relative spot at each Y interval, but mobiles go between those spots and the sorting becomes ambiguous because of this.

    So after fiddling around a bunch with shaders and shelving that as just ineffective as a solution, I went back to basics and fixed my issue in the first attempt which is very sad. The reason I missed this before was I was incorrectly using my collider position as what the sorting position is which is wrong as it wasn't at the same spot (close enough that my error wasn't obvious, but off enough to look like the issue was not solvable).

    So the solution, pretty simple:
    1. Ensure your character graphic sorting point is under the character. You can either use a pivot point change on the graphic, or change the graphic itself (I tried both, and both seem to work). To change this you have to both change the settings on the sprite itself and the sprite render. You want your graphic to have some room below it to deal with some edge clipping, but don't need too much (mine is using 3 pixels from a 32x32 sprite).
    2. Figure out which tile the sorting point is in. Now, since the sorting point is now your transform.position of the sprite, this is pretty easy. Just use the grid or the tilemap's worldtocell function. Only trick to note here is to effectively ignore the Z for now since you'll be dynamically altering it. So probably do the worldtocell on a new Vector3 using only the position's x and y and a baseline, usually the ground Z.
    3. Next convert that Vector3Int back into a Vector3 to get the default position of the tile.
    4. Find the relative position within the cell of your character using your transform.position - defaultposition.
    5. Inspect the Y coordinate of this and figure out if you are in the bottom half of the ground diamond. For me this was simply Y < .25. If your anchors for your grid are different though you may have to test out values (it should be a .25 increment of some kind).
    6. If the character is in the in the bottom half of the diamond, set their Z to ground level + 1, else ground level + 2.

    Do that in your update routine and sorting should work out appropriately now.
    Here is the code I used on my test script:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Testscript2 : MonoBehaviour
    6. {
    7.     // Start is called before the first frame update
    8.     void Start()
    9.     {
    10.        
    11.     }
    12.  
    13.     public Vector3 relativePos;
    14.     public Vector3 pos;
    15.  
    16.     // Update is called once per frame
    17.     void Update()
    18.     {
    19.         pos = new Vector3 (transform.position.x, transform.position.y, 0);
    20.         Grid g = GameResources.Current.GameGrid;
    21.         Vector3Int tilepos = g.WorldToCell(pos);
    22.         Vector3 tileworldpos = g.CellToWorld(tilepos);
    23.         relativePos = pos - tileworldpos;
    24.         if (relativePos.y < .25)
    25.             transform.position = new Vector3(transform.position.x, transform.position.y, 1);
    26.         else
    27.             transform.position = new Vector3(transform.position.x, transform.position.y, 2);
    28.     }
    29. }
    30.  
    The only way this seems to go awry is if you allow your character to move into tiles (like you're going into a cave or the like). You'd have to experiment more if that is the case, although I suspect it is just a matter of keeping the Z always at 1 in that case.

    Damn, I've been at this issue for weeks, sad that the solution was one I attempted real early but got just a bit wrong.
     
    naknuknik and Spriterman21 like this.
  16. Spriterman21

    Spriterman21

    Joined:
    Mar 6, 2020
    Posts:
    5
    Wow, you just saved me. This is exactly what I needed. Thank you!