Y sort doesn't work

BatteryBattery Posts: 26Member
edited December 1969 in 2D
Hey, frustrating problem here:<br /><br />So I've got a y sort node and parented to that node is a tile map (with y sort enabled) and the player (a kinematic body with sprites as children) but it wont y sort at all.<br /><br />  YSort<br />  |_Tilemap<br />  |_Player(kinematic2D)<br />    |_Sprite1<br />    |_Sprite2<br />    |_Animation<br /><br />When I make my player a child of the tile map with Y sort enabled it half works. But the sprite animations have changes in Z values, so various parts of the character pop through. So, once again, Y sort doesn't work. <br /><br />  YSort<br />  |_Tilemap<br />    |_Player(kinematic2D)<br />        |_Sprite1<br />        |_Sprite2<br />        |_Animation<br /><br />The problem is I'm dynamically loading in different areas, and each area can any number of object tile maps, plus an unknown amount of NPC's, all of which needs Y sorting. I want to be able to dump everything in a Y sort node so that I don't have to keep adding everything as a child of the last tile map and then re-jigging the tree every time I remove a tile map. <br /><br />  YSort<br />  |_Tilemap1<br />    |_Tilemap2<br />        |_Tilemap3<br />          ... and so on<br />              |_NPC1<br />              |_NPC2<br />              |_NPC3<br />              |_Player<br /><br />And even if I did do that, Y sort doesn't work with animations that change the Z index anyway. <br /><br />I aware that Y sort doesn't sort children of a Y sorted object, but then why does it mostly work (bar animations) with player (which consists of multiple children) as a child of a tile map with Y sorted enabled? <br /><br />Also, if it doesn't work with children, then all the parts my NPCs would have to have to exist as separate children of the Y sort node, which would break the encapsulation they have. <br /><br />  YSort<br />  |_Tilemap1<br />    |_Tilemap2<br />        |_Tilemap3<br />              |_NPC1_head<br />              |_NPC2_body<br />              |_NPC1_legs<br />              |_NPC1_weapon<br />              |_NPC2_head<br />              |_NPC2_body<br />              |_NPC2_legs<br />              |_NPC2_weapon<br />              ... and so on ....<br />              |_Player_head<br />              |_Player_body<br />              |_Player_legs<br />              |_Player_weapon<br /><br />Then because I can no longer put each NPC and player in their own top level node, it becomes harder to spawn them into the level dynamically. So which ever way you look at it, the Y sort node doesn't work.<br /><br />Any ideas?


  • BatteryBattery Posts: 26Member
    I've been trying to solve the problem with scripts. The plan was to work out what cell in a tile map the player/NPC is on, then get that tile's y positions and set it's Z index depending on if the player is above or below the tile's y position.<br /><br />However, it's does not appear possible to set an individual's tile Z index because while you can get a tiles name/ID you can't get the individual tile object (which should be a sprite).<br /><br />I can't adjust the tile maps overall Z index as that would upset relationships between NPC's and the tile map. So I thought I'd just each NPC and the player instead. Except you can't get an individual tile's y position to tell if they're above or below it. Fast running out of ideas here.<br /><br />There must be a way to Y sort a scene more complex scenes?
  • chitogechitoge Posts: 6Member
    What I would do here is just remake your implementation, because looking at those nested Tilemaps, it seems more complicated than I think it needs to be. <br /><br />You have multiple body parts of an NPC under a Tilemap, and you want to be able to sort their Z and Y axes. I would make them a separate scene entirely so you can implement your scripts and changes, and they are a top level node alongside your Player, so Y sort should probably work.<br /><br />Maybe have 3 main groups under Y sort: Player, Non-Player, and a Node2D that stores all dynamically generated Tilemaps.<br /><br />I guess the Z values override the Y sorting since the player is literally above the others so that's why they won't work, maybe change the node ordering in the node tree when Z changes happen and the Tilemap node is rendered after the Player node because of the ordering.<br />
  • BatteryBattery Posts: 26Member
    Thanks for the suggestions! :D Those crazy nested trees are exactly what I'm trying to avoid.<br /><br />
    on 1466879612:
    <br />You have multiple body parts of an NPC under a Tilemap, and you want to be able to sort their Z and Y axes. I would make them a separate scene entirely so you can implement your scripts and changes, and they are a top level node alongside your Player, so Y sort should probably work.<br /><br />Maybe have 3 main groups under Y sort: Player, Non-Player, and a Node2D that stores all dynamically generated Tilemaps.<br />
    <br /><br />That's what I'm doing, but Y sort will not work. It appears that it only works on direct children of the Y sort. So this doesn't work:<br /><br />  YSort<br />  |_Objects(Node2D)<br />    |_tilemap1<br />    |_tilemap2<br />  |_NPC(Node2D)<br />    |_NPC1<br />    |_NPC2<br />  |_Player<br /><br />Curiously, if I start with this set up it works:<br /><br />  YSort<br />  |_Tilemap<br />  |_Player<br /><br />But if you have more than one tile map, then all but the first wont work (but will if they have different tile sets). If I just have the Y sort and the player, and then load in the tile map from another scene it doesn't Y sort, even though the resulting tree is exactly the same. So, I can only conclude that Y sort doesn't work. <br /><br />I tried using individual sprites for objects. But this creates it's own problems. If I load all the sprites into the Y sort node it works fine. But if I group all the sprites into a Node2D (or any other node) it wont. The problem is the objects need to be sensibly grouped so that I can unload them when player moves out of that area and the Y sort node just becomes a mess of sprite nodes. Basically, I'm creating a large top-down world and rather than having one massive map, I'm breaking down into chunks and loading them in/out as needed. Everything works great, except where things need Y sorting.<br /><br />Your spot on about the animations. Y sort only seems to sort properly if everything under the node has the same Z index. I managed to solve this by having a function track in the player animations that moves the order of the player sprites around in their tree rather than changing each parts Z index. It strikes me as an incredibly hacky solution, that does exactly the same thing as animating the Z index, but using more processes and effort. At least it works with the Y sort node. One problem solved!
  • BatteryBattery Posts: 26Member
    Right, after lots of trial and error it appears you can only have one one Y sorted tile map at a time. <br /><br />So, I've put every tile that needs sorting into one massive tile map. My main scene looks like this:<br /><br />  Node2D<br />    |_ TileMap (Y sort enabled)<br />      |_Player<br /><br />The tile map in main scene is empty. Then when I load in a new area I just copy the cell indexes and position from the area's tile map into the main tile map:<br /><br />
    <br />var sortNode = get_node(&quot;TileMap&quot;)<br />var area = preload(&quot;res://testArea.scn&quot;)<br />var top_node = area.instance()<br /><br />if top_node.has_node(&quot;SortMap&quot;):<br />&nbsp;  var sort_map = top_node.get_node(&quot;SortMap&quot;)&nbsp;  <br />&nbsp;  for tile in sort_map.get_used_cells():<br />&nbsp; &nbsp; &nbsp; var posi = sortNode.world_to_map(pos)<br />&nbsp; &nbsp; &nbsp; sortNode.set_cell(tile[0] + posi.x, tile[1] + posi.y, sort_map.get_cell(tile[0], tile[1]))<br />&nbsp;  sort_map.free()<br />
    <br /><br />So the main tile map doesn't get ridiculously big I keep track of all the added tiles and clear them when I free an area. Then all other sprites and nodes that need Y sorting are added as a child to the main tile map. Here's it in action:<br /><br /> /><br />The areas are deliberately small so I can see them loading in and out. It's far from an ideal solution. It needs a load of extra code to load in an area adding to the running costs, and having to put everything in one massive tile map takes away from the organisational benefits of a tile map.<br /><br />Ultimately, I've come to tile maps are quite limited and become cumbersome when trying to do anything beyond a simple level. Still, beats having everything as a separate sprite node.
  • chitogechitoge Posts: 6Member
    Looks great! All I can say is keep thinking and coding and you'll eventually find solutions to dynamic map loading with automatic Y sorting. That's what I've been doing at the moment on my roguelike project.<br /><br />The only things I can suggest for dynamic loading is doing something like constantly checking if this tile is within a set boundary (minimum and maximum), or using the CanvasItem hide() signal to free every tile that is no longer on camera. This way dynamic loading looks more dynamic instead of dynamic 'chunk' loading in your demo.<br /><br />I'm not sure if this works in Godot but I would try setting the Z-axes of the player and NPCs to their Y value set_z(get_pos().y), that's how I did it in GameMaker Studio.
  • BatteryBattery Posts: 26Member
    Cheers man  :D<br /><br />That's an interesting idea. The difficulty with that is that each area is it's own scene, which means I can create a large map out of small sections, and to load in even smaller sections of each scene would require more code without much performance benefit. The actual areas will be larger in size, so you wont see them loading in and out. Also, checking if an object is in the camera or not as straightforward as you might think (really, camer2D needs a [tt]is_in_frustum()[/tt] method).<br /><br />That was one of the ideas I tried, but you can't get the z value of individual tiles, just the whole map, so it wouldn't work for y sorted tile maps.

Leave a Comment

BoldItalicStrikethroughOrdered listUnordered list
Align leftAlign centerAlign rightToggle HTML viewToggle full pageToggle lights
Drop image/file