• Hello [name]! Thanks for joining the GMC. Before making any posts in the Tech Support forum, can we suggest you read the forum rules? These are simple guidelines that we ask you to follow so that you can get the best help possible for your issue.

 Set object's draw order on "instance_create_layer"

M

MarceloP

Guest
Hello guys!

I'm working on a prototype and I've reached a moment where I'd like to create some objects on a Instance Layer. I called "instance_create_layer" and got what I wanted. But since I have more than one thing that will be "dynamically instantiated" I ran into a problem.

When calling "instance_create_layer" you can't tell if the new created object will be draw OVER or UNDER the other objects that were already created. This seems silly, but I don't know in which order my objects will be created and, even if I knew it, I can't set the new instances to be in the drawing order that I want to.

I mean, for simplicity I'd guess that GM probably takes the elements from the layer and draws one after the other, in the sequence they were added to the layer. But no, it seems that (maybe for speed) they actually run it backwards, drawing from the latest added to the first added to the layer, and I can't tell GM to do different.

Some would say for me to create a new layer for every object or better, use depth on everything; but what's the point of a Instance Layer that doesn't allow me to say what comes in front of what? This would only be good for the editor part and, to be real, even make harder for dynamically generated objects to be correctly drawn in those layers.

Layers are a great improvement to GM2, but I do think this layer/depth integration is still way too crude. There should be a better integration of those 2 things in such a way that you could set the depth and still be part of a layer, since it simplifies all matters like setting all elements to invisible, deactivating all elements, and so on...

Anyone has any suggestion in which way I would be able to draw my dynamic instances in a certain order without using the depth system (manually working the depth of all instances)?
 
Last edited by a moderator:

Nocturne

Friendly Tyrant
Forum Staff
Admin
There is NO guaranteed draw order for items on the same layer. This is because the engine will try to batch things to draw in the most optimal way and it may not always be the same. There are already two mechanisms for guaranteeing draw order (as you have already realised): Use individual layers, or use the "depth" value instead of layers. Alternatively, create a list and order them as you wish then draw them manually in a controller object on the layer you need them on (this is probably the most flexible method as it gives you complete control over what gets drawn).
 
The problem I ran into with using the built-in depth variable was that changing an instances depth causes GMS 2 to make an internally managed layer at that depth (even if its at the same depth as a user created layer in the Room Editor). That managed layer is not accessible in code, as calling layer_get_id() just returns -1 for that instance.

It also caused some sprite flickering for a given depth. For me, it happened when the instance was transitioning from a depth of > 1 to a depth of < 1.

I have seen a few other threads with similar issues when using depth = -y that cause sprite flickering, and various work-arounds.

Also, my instances depths values are fractional, so they could be 1.2, 2.7 etc... but I found that GMS 2 must be rounding that value somehow, so all instances that have a depth between 1 and 2 will all be on the same layer, leading to the same issue with draw order.

It would be great if there was a built-in z value for instances, and then GMS 2 handled draw order using that z value. All instances could be on the same layer and still be drawn correctly this way.

As it stands now, it seems we have to manage the draw order ourselves.

As I didn't like what setting the depth was doing, I used the technique in this forum post:

https://forum.yoyogames.com/index.p...rity-list-nested-list-grid-binary-list.13425/

I used a sorted ds_list, with the instance id and z value bitshifted together.

However, I still had the same problem of instances on the same layer and not being able to control their draw order.

So I added another instance variable called draw_priority.

I then multiply the z value by 10000, and then add the draw_priority value to that, then perform the bit shift.

Camera End Step
Code:
if ( update_draw_list )
{
    ds_list_clear(draw_list)
   
    with ( o3D )
    {
                var _val = (id | ((z_3D * 10000) + draw_priority) << 32) //* 10000 //- Store layer priority in last 2 digits
           
               // E.g. For a depth(z_3D) value of 0.01
               // 0.01 * 10000 = 100 ==> plus draw_priority[0..99] ==> gives value of 100->199 for depth sorting
               // (z_3D * 10000) + 0-99 "priority"
               
                ds_list_add(o3DCamera.draw_list, _val)   
    }
   
    ds_list_sort(draw_list, false)
}
Camera Draw Event
Code:
var _list_size = ds_list_size(draw_list)

for ( var i = 0; i < _list_size; ++i )
{
    var oID = draw_list[| i] & $ffffffff; // Extract the instance id.
   
    with ( oID )
    {
        event_user(0)  // Custom Draw Event
    }
}
I'm not sure this is the perfect solution, as I've recently changed my code to have all my instances on the same layer, and just sort them ONLY using my custom z_3D value, but this solution works for me when I have multiple layers. (As long as you don't have more than 99 objects in the same location on the same layer and need them sorted in a particular order :) )
 
M

MarceloP

Guest
Thank you for both answers. Yeah, those solutions are pretty good. i'll probably change everything to depth and manage them myself.

I know it may be far beyond any point for this to be changed but, from a engine's perspective, the insertion of layers that do not change the whole depth system is a mix that doesn't seem to be working well. The problem with creating a z-index in within the layer is that, to tell the truth, it would create another variable that changes depths in another new different way.

The other suggestion of not returning -1 and actually returning an "application_layer" would be great, since we'd be able to use all layer functions in it.

To actually say what I think would be the best (although I've already stated "I know it may be far beyond any point for this to be changed", since YoYo probably won't change all of this again, though I think they should), I'll suggest this:
Depth would still be the way it was on GM1.4, layers would only be an internal structure for all layer functions (more like a easy list for you to access all elements). The only difference is that layers wouldn't be a restriction for any dynamic change on the depth. How? Well, setting layers depths on the IDE would only set a initial depth state for the objects.

The way this current way seems to have been created is: GM1.4 had depths. We want layers now, and they can be of backgrounds and tiles (things that doesn't have the depth property). Therefore, if a user was to change the depth, it would mess the layers and then we need to pull the object out of the layer to a "managed" layer so the managed is controlled differently and apart from the layer system.

But if you keep the depth as the main controller of depth (really as if a zindex for every single thing) and layer were merely an way of packing those elements (which they already were) and the starting point of those, the only thing that should be worked is a way for "background layers" and "tileset layers" to respect the depth system of objects as well, independently (comparable to an object, but much simpler). For the dynamic changing of depths of objects, no problem, let the object change its depth at will, no obstruction, and still be packed inside that one layer.

I don't think that the layer system should be a wall for coding dynamic depths, as a lot of people are facing... I mean, creating a managed layer is ok, but this integration takes away the advantage of layers and puts you back to the old depth systems that were implemented on GM1.4 (like depth=-y), without the advantage of layers.

Another possible solution that would be even simpler (but maybe no that efficient), is to change the function instance_create_layer(x, y, layer, object, [layer_offset]), where if nothing was passed would follow the current functionality and if a position would be passed the function would actually draw/put that object in that layer, but with an depth offset of "layer_offset". If, for some reason the engine detects that this "layer_offset" is out of bounds, or beyond the next layer's depth (assuming layers depths are indexed), it can simply crash (or even put it on the maximum offset possible before the next layer). Then coders would be able to set the depth inside the IDE of each layer and also use the "gaps" in between then to create order in all instances that are created there.

Well, I guess those are pretty pretty late suggestions, but the last one may be "implementable" by YoYo, and I would strongly suggest them to do so.
More new ideas would be very nice too xD
 
Last edited by a moderator:
Top