GameMaker Sprite depth

T

Thijmen Langendam

Guest
So currently my game spanwns in a bunch of trees, however it looks like GameMaker first checks which of the objects is on the left, and if it's on the left, it'll overlap anything that's on the right of it, causing problems like these:



Is there a way to fix this? So that it checks which object is higher rather than to the left. I mean i could edit each and every depth however the maps get quite big and that'll mean that the depths will go into the millions.

Does GameMaker allow decimal depths? Because then i could add (obj_y / room_height) to the depth, if not, are there other fixes that do not include editing depths?
 
D

drowned

Guest
gamemaker is not checking which object is on the left, it's just drawing it later than it's drawing the one on the right.

Also, as far as I can tell, left-to-right doesn't matter in your game's perspective. If the second tree were to the bottom-left of the first tree, it should still be in front of it. Maybe change your spawner to start from the top of your room and work its way down?
 
T

Thijmen Langendam

Guest
This is a very in-depth topic and has been discussed multiple times.

Youtube by FriendlyCosmonaut

You can find code example in the YYG dungeon demo.

Post by Ariak discussing the performance of different methods.
https://forum.yoyogames.com/index.p...rity-list-nested-list-grid-binary-list.13425/

Post by me explaining a different method.
https://forum.yoyogames.com/index.php?threads/depth-sorting-method-for-gms2-objects-sprites.42868/
Ah that worked great, however i'm now receiving the following glitch:

 
J

jbrooksdev

Guest
I usually use just depth = -y upon creation if the object never moves.
 
T

Thijmen Langendam

Guest
so which method did you use to get to this point?
The video tutorial of FriendlyCosmonaut, basically for each instance it gets the y value, and sorts it, then draws the lowest y value first
 
D

drowned

Guest
So if you're manually drawing all of the trees in an ordered, unchanging list, why would adjacent trees on the same y position change depth? Are you running this sorting algorithm every step?
 
T

Thijmen Langendam

Guest
So if you're manually drawing all of the trees in an ordered, unchanging list, why would adjacent trees on the same y position change depth? Are you running this sorting algorithm every step?
Yes every step, as the tutorial also does.
 
K

kevins_office

Guest
Yes every step, as the tutorial also does.
If you use the binary list sorting method as explained by Ariak then you wont have that problem because the instance ID is part of the sort.
Meaning the list will never randomly resort objects of the same Y value, because they will be sorted by Y first then by the ID which will never change.
You can use binary list sorting with the FriendlyCosmonaut method.
 
D

drowned

Guest
Even still, why run it every step? Run your spawner, run the sorting script once, set your depths, and be done with it... right?
 
T

Thijmen Langendam

Guest
Even still, why run it every step? Run your spawner, run the sorting script once, set your depths, and be done with it... right?
Well the idea is that, because it's a top down game, you want to be in front of an instance, e.g. a tree, if you're "lower" on the screen compared to that instance, and to do this, you basically have to check every step.

However i'm now trying to find a different approach than the depth system proposed by FriendlyCosmonaut as the amount of instances that have to be re-drawn every step currently lag my game to 5-10 steps a second.
 
D

drowned

Guest
wouldn't it make more sense to just reorder the player's depth each step rather than sort and assign every single tree?

Edit: I had a thought... what if each tree is two separate sprites, and the leaves/upper trunk are always at a depth above the player and the lower trunk is always at a depth behind the player. Then you can run your sorter once, to deal with the tree-to-tree depth issues, and you never have to do anything for the player in a step event.
 
T

Thijmen Langendam

Guest
wouldn't it make more sense to just reorder the player's depth each step rather than sort and assign every single tree?

Edit: I had a thought... what if each tree is two separate sprites, and the leaves/upper trunk are always at a depth above the player and the lower trunk is always at a depth behind the player. Then you can run your sorter once, to deal with the tree-to-tree depth issues, and you never have to do anything for the player in a step event.
This is what i did initially, didn't think of running this sorter once on it though, i'll give it a go and will share the final result when it's a success!
 
T

Thijmen Langendam

Guest
I had a thought... what if each tree is two separate sprites, and the leaves/upper trunk are always at a depth above the player and the lower trunk is always at a depth behind the player. Then you can run your sorter once, to deal with the tree-to-tree depth issues, and you never have to do anything for the player in a step event.
Got it working, after a bit of tweaking etc. Thanks to your bright mind :D
 
T

Thijmen Langendam

Guest
If you use the binary list sorting method as explained by Ariak then you wont have that problem because the instance ID is part of the sort.
Meaning the list will never randomly resort objects of the same Y value, because they will be sorted by Y first then by the ID which will never change.
You can use binary list sorting with the FriendlyCosmonaut method.
I took a look into this, but i tweaked the FriendlyCosmonaut's way of the depth system, and now my "depth list" is only generated once, yet 2 neighbouring objects with overlapping sprites will still show those "same height, same depth" glitch/artifact :/
 
D

drowned

Guest
Find two instances of overlapping trees with the same y value and then check their depths in the debugger
 
T

Thijmen Langendam

Guest
Find two instances of overlapping trees with the same y value and then check their depths in the debugger
Tree 1:

Tree 2:

Note that i draw them in a layer above the player, and then draw them in order from left-right, top-bottom
 
T

Thijmen Langendam

Guest
So give them different depths
Well the problem with that is that i have hundreds, and for big maps thousands of instances that might be overlapping, so checking all instances for same y values and close x values wouldn't be really performance friendly. What i did think of was just moving that object one pixel to the south or north so that they aren't overlapping any more. However i'm not sure if GameMaker has a built in function that can move objects. If not, i might want to destroy one of the two trees alltogether as the chances of overlapping trees is very slim (3-4 per level)
 
D

drowned

Guest
The spawn only happens once at the beginning right? So who cares if it's performance friendly? And you don't have to check for same x or y, just check for collision with another tree.

However i'm not sure if GameMaker has a built in function that can move objects
huh? obj.y++ ?

Edit: Or put every other tree on a layer with depth 101. If you're drawing from left to right then that guarantees you that one of two adjacent trees will always be in front.
Edit2: Nevermind my edit suggestion, that could potentially cause trees overlapping vertically to be drawn with the lower tree on top.
 
Last edited by a moderator:
T

Thijmen Langendam

Guest
The spawn only happens once at the beginning right? So who cares if it's performance friendly? And you don't have to check for same x or y, just check for collision with another tree.


huh? obj.y++ ?

Edit: Or put every other tree on a layer with depth 101. If you're drawing from left to right then that guarantees you that one of two adjacent trees will always be in front.
Edit2: Nevermind my edit suggestion, that could potentially cause trees overlapping vertically to be drawn with the lower tree on top.
So i fixed it in a performance friendly way compared to all other possible fixes for this problem.
I found out that the problem was that on each call of the draw function, i re-sorted the grid that stored the drawing-order of all trees.
Of course if 2 trees had the same y value they had the chance to be switched in this grid when it was getting re-sorted.
So i basically only sort the list once instead of on every draw call, which is also way better on performance.
 
K

kevins_office

Guest
I found out that the problem was that on each call of the draw function, i re-sorted the grid that stored the drawing-order of all trees.
Of course if 2 trees had the same y value they had the chance to be switched in this grid when it was getting re-sorted.
So i basically only sort the list once instead of on every draw call, which is also way better on performance.
This is what i tried explaining before.
The binary list sorting method has better performance than the sorting method used by FriendlyCosmonaut.
And it has the added benefit of not re-ordering positions for objects with the same Y value due to the fact the instance ID is part of the sorting.
If you resort the list because you added or removed an object / instance, it wont change the order for things with the same Y value.
 
T

Thijmen Langendam

Guest
This is what i tried explaining before.
The binary list sorting method has better performance than the sorting method used by FriendlyCosmonaut.
And it has the added benefit of not re-ordering positions for objects with the same Y value due to the fact the instance ID is part of the sorting.
If you resort the list because you added or removed an object / instance, it wont change the order for things with the same Y value.
For future use, can you refer me to the Gamemaker Studio 2 documentation page(s) of the binary list sorting?
 
K

kevins_office

Guest
For future use, can you refer me to the Gamemaker Studio 2 documentation page(s) of the binary list sorting?
Its more of a concept, not a built in function.
Instead of a 2D list where you store the ID in one column and the Y value in a different column which then you sort by.
You combine the Y value and the ID into a single number stored in a 1D list. Sort the single column list, then split the number back into Y value and ID.

In Ariak's advice he uses bit shifting to accomplish this (vs using math).
Depending on your project you would have to customize the code depending on how you are keeping track of what needs to be sorted.
But here is a simplified example using a layer to sort objects, not taking into account other things on the layer or whats visible on screen, etc.
Code:
ds_list_clear(depthList);  // ds_list was created previously
var loop = 0;
var elements = layer_get_all_elements(layer_id);
repeat (array_length_1d(elements)) {
   if (layer_get_element_type(elements[loop]) == layerelementtype_instance) {
       var thisInst = layer_instance_get_instance(elements[loop]);
       ds_list_add(depthList, (elements[loop] | thisInst.y << 32) );
   }
   loop++;
}
ds_list_sort(depthList, true);
Code:
var loop = 0;
repeat (ds_list_size(depthList)) {
   var element_id = depthList[| loop++] &$ffffffff;
   with (layer_instance_get_instance(element_id)) event_perform(ev_draw, 0);
}
Ofcourse if you are doing a sorting method based on an object or parent name then your code would look different on how you loop to build the list.
 
Top