Object Draw Order and Depth

With the change in how depth is handled in GMS2, drawing sprites that have dynamic depth in a 2D world has gotten slightly more complicated. Here’s a basic system and set of scripts that allow each object to be drawn at the proper depth.

The final results look something like this:

 

First, I create a Controller object called DrawOrder. This will handle the final draw operations of all objects that need depth sorting all in one Draw event.

DrawOrder object Create event

/// @description Init DrawOrder

//grid of objects (id, depth, script)
objects = ds_grid_create(3, 0);

Pretty straightforward. We create an empty 3 column grid to store each objects ID, Depth, and the draw script to run (We’ll come back to this).

DrawOrder object Step event

/// @description Sort draw order

//sort objects
ds_grid_sort(objects, 1, true);

The main benefit of using a DS Grid is so we can easily sort by the 2nd column, depth. This will order all the object references by whatever depth we set from top to bottom.

DrawOrder object Draw event

/// @description Draw all objects
for(var i = 0; i < ds_grid_height(objects); i++){
    var oid = ds_grid_get(objects, 0, i); //object id
    var script = ds_grid_get(objects, 2, i); //script
    with(oid){
        script_execute(script, oid);
    }
}

ds_grid_resize(objects, 3, 0);

This is the main code for this object. We loop through the grid and then execute the attached draw script for each row. Once we’ve drawn each object, we clear out the object grid so it can be refreshed next step.

Now, we have a couple of scripts to actually insert objects into the DrawOrder list: default and extended.

draw_at_depth(id, depth)

///draw_at_depth(id, depth)
///@param id
///@param depth

var oid = argument0;
var dep = argument1;

var row = ds_grid_height(DrawOrder.objects); //get next row
ds_grid_resize(DrawOrder.objects, 3, row + 1); //resize grid
ds_grid_add(DrawOrder.objects, 0, row, oid); //object id
ds_grid_add(DrawOrder.objects, 1, row, dep); //depth
ds_grid_add(DrawOrder.objects, 2, row, draw_object); //default script

This is the default function to draw an object. It has a default draw script that will run.

draw_at_depth_ext(id, depth, script)

///draw_at_depth(id, depth, script)
///@param id
///@param depth
///@param script

var oid = argument0;
var dep = argument1;
var script = argument2;

var row = ds_grid_height(DrawOrder.objects); //get next row
ds_grid_resize(DrawOrder.objects, 3, row + 1); //resize grid
ds_grid_add(DrawOrder.objects, 0, row, oid); //object id
ds_grid_add(DrawOrder.objects, 1, row, dep); //depth
ds_grid_add(DrawOrder.objects, 2, row, script); //custom script

The only difference here is we’re allowing a customized script to be included that will be executed at draw time.

draw_object(id)

///draw_object(id)
///@param id

var oid = argument0;

with(oid){
    draw_sprite_ext(sprite_index, image_index, x, y, image_xscale, image_yscale, image_angle, c_white, 1);
}

And here’s the default draw script. Inside the attached object, we simply draw the sprite the same way draw_self() works.

That’s it! Now we have a basic system that will draw each object according to depth and can even execute a custom draw script in case there are extra things being drawn for an object.

Examples:

Player object Draw event

/// @description Draw Sprite

draw_at_depth_ext(id, bbox_bottom, player_draw);

Building object Draw event

/// @description
draw_at_depth(id, y);

Leave a Reply

Your email address will not be published. Required fields are marked *