GMS 2 Depth sorting draw order (solved)

Discussion in 'Programming' started by Vintendi, Dec 5, 2018.

  1. Vintendi

    Vintendi Member

    Joined:
    Jan 13, 2018
    Posts:
    41
    Basically I'm adding all the instances within the view to a ds_grid which is then sorted by y position in the room. It then loops through the grid performing every instances draw event in order. The problem is that if two instances have the same y position in the room they begin to flicker past each other if they are overlapping. I was hoping someone had a solution to this.

    Code:
    //--RESIZE GRID
    var instNum = instance_number(oDepthParent);
    var dgrid = depthGrid;
    ds_grid_resize(dgrid, 2, instNum);
    
    //--ADD INSTANCES
    var yy = 0;
    with (oDepthParent) {
        if !(oPlayer.push) {
            dgrid[# 0, yy] = id;
            dgrid[# 1, yy] = y;
            yy++;  
        }
    }
    
    //--SORT GRID (ASCENDING)
    ds_grid_sort(dgrid, 1, 1);
    
    //--LOOP THROUGH GRID AND DRAW
    var inst;
    yy = 0;
    repeat(instNum) {
        inst = depthGrid[# 0, yy];
        with (inst) {
            event_perform(ev_draw, 0);  
        }
       
        yy++;
    }
    
     
  2. Vintendi

    Vintendi Member

    Joined:
    Jan 13, 2018
    Posts:
    41
    SOLVED: Changed code to
    Code:
    //--RESIZE GRID
    var instNum = instance_number(oDepthParent);
    var dgrid = depthGrid;
    ds_grid_resize(dgrid, 2, instNum);
    
    //--ADD INSTANCES
    var yy = 0;
    with (oDepthParent) {
        if !(oPlayer.push) {
            dgrid[# 0, yy] = id;
            dgrid[# 1, yy] = y;
            yy++;   
        }
    
    }
    
    //--SORT GRID (ASCENDING)
    ds_grid_sort(dgrid, 1, 1);
    
    //--SCAN GRID FOR OVERLAP
    for(var i=1; i<ds_grid_height(dgrid); i++)
    {
        if dgrid[# 1, i] == dgrid[# 1, i-1] && id.object_index != oPlayer
        {
            dgrid[# 0, i].y += 0.1;   
        }
    }
    
    //--LOOP THROUGH GRID AND DRAW
    var inst;
    yy = 0;
    repeat(instNum) {
        inst = depthGrid[# 0, yy];
        with (inst) {
            event_perform(ev_draw, 0);   
        }
        
        yy++;
    }
    
     
  3. ph101

    ph101 Member

    Joined:
    Jun 20, 2016
    Posts:
    387
    One thing to think about here is that because you are looping through the grid twice its going to be slower than it needs to be (also, hopefully you are not chagning grid size every step? only when you make an instance. Also you only need to sort the grid when something moves). Also by performing an if comparitor for every entry it is going to be slower than perhaps it needs to be. This might not be a problem depending on your game, but one idea is to incorporate the x value to your sorting for y. By how much depends on what you want for your game and if objects can exist in the same space. For example in isometric games you can sort with a depth -x-y which helps prevent this issue, it means you dont need to do a double loop, just thought it worth mentioning. Final point very minor is that when you want an ascending variable it has sometimes been said that a for loop is faster, given you run it every step you may very slightly better performance using a for loop rather than repeat for your draw loop yy value.

    (Actually one other final final point is if you had a control object just draw the objects directly rather than perform the draw event it could be faster still? I'm not sure n that just a thought though!)
     
  4. Vintendi

    Vintendi Member

    Joined:
    Jan 13, 2018
    Posts:
    41
    Thanks for the suggestions. Currently there has been a minor performance hit (currently not noticeable @ 100-500 instances). I am currently disabling any object outside the view so the entire world isn't being added to the list. I'm definitely tweaking the code to only update when the instance number changes to save some performance. That last point is interesting, it wouldn't work with my game because some items require specific draw sequences such as a UI being drawn under the sprite. I was also wondering if you could explain the isometric depth sorting or link a tutorial. I didn't quiet understand what your mean't.
     
    Last edited: Dec 5, 2018
  5. ph101

    ph101 Member

    Joined:
    Jun 20, 2016
    Posts:
    387
    I meant was basically if you had

    Code:
    dgrid[# 1, yy] = y + x;
    
    then if an object is at the same height but slightly to the right it will be on top (or is that behind?), either way, could prevent the problem you seem to have without a second loop. Maybe worth a try but it could cause a problem if something is diagonally off to the side having the wrong depth in some situations, its quite hard to say without knowing what perspective you are using, and then arguably you could use 0.1 * x or something instead but that might end up being slower than a second loop, also if its running fine now, it doesn't really matter (in isometric projection using the cartesian x + y for draw order can work because you are viewing as from a diagonal projected space, but this probably is not really useful, you can search the forum or google for isometric tutorials)
     
  6. Vintendi

    Vintendi Member

    Joined:
    Jan 13, 2018
    Posts:
    41
    Thanks for expanding on that. After some optimisation testing I found that the sorting and updating had a small performance impact. The majority of the performance hit is down to the event_perform. I'm currently trying to figure out how to optimise this further so I can just use draw_self().
    Here is a spreadsheet with the results if you are interested:
    https://docs.google.com/spreadsheets/d/1SXGnf4TIMFnetvu1FY1bNn7v86CrP_WTi7Z1iLRHUSs/edit?usp=sharing

    Altered code:
    Code:
    //--RESIZE GRID
    var instNum = instance_number(oDepthParent);
    var dgrid = depthGrid;
    
    if instances != instNum
    {
        ds_grid_resize(dgrid, 2, instNum);
    
        //--ADD INSTANCES
        var yy = 0;
        with (oDepthParent) {
            if !(oPlayer.push) {
                dgrid[# 0, yy] = id;
                dgrid[# 1, yy] = y+x*0.1;
                yy++; 
            }
        }
    
        //--SORT GRID (ASCENDING)
        ds_grid_sort(dgrid, 1, 1);
      
        instances = instNum;
    }
    
    //--LOOP THROUGH GRID AND DRAW
    var inst;
    for(yy=0; yy<instNum; yy++) {
        inst = depthGrid[# 0, yy];
        with (inst) {
            event_perform(ev_draw, 0); 
        }
    }
    
    [NOTE]: changing repeat loop to for loop had not noticeable impact.
     
    Last edited: Dec 6, 2018
  7. ph101

    ph101 Member

    Joined:
    Jun 20, 2016
    Posts:
    387
    Nice, good to see these figures. IMO you probably shouldn't get too bogged down with this at this stage though unless you actually are having issues. Its commonly suggested to avoid premature optimisation because you will waste your time making a possibly slightly faster drawing system but end up with no game. Its questionable if you need to at all - it also depends on how many instances you have, mostly event perform is going to be fine for your needs if its what you have. I dont really know why you suggest draw_self or how that would differ in any way from event perform draw as you would still be getting the slow down from using a with structure. My suggestion is to have the contol object draw the sprite of the instance directly and in the sorted order and have the instances themselves invisible (again though, this probably isnt needed).

    Btw I've just noticed you seem to only sort the grid only every time you have a new instance. It needs to be everytime an instance moves as well - and this could be everystep (otherwise.. the grid wont be reflecting their positions and draw order) unless they are all static. Disclosure - i'm not sure the x * 0.1 is a great idea, was just a passing thought. If you want to truly find the most optimal way for depth sorting forum member Ariak has studied it closely, https://forum.yoyogames.com/index.p...rity-list-nested-list-grid-binary-list.13425/, and I might add that although it may be marginally slower, depending on your layer structure depth still works in GM2 and as far as I can see is not technically depricated?
     
  8. Vintendi

    Vintendi Member

    Joined:
    Jan 13, 2018
    Posts:
    41
    That's a good point, I didn't have anything moving apart from the player so I didn't notice this. I'll look further into the x * 0.1 idea when it becomes more of an issue. Also I was more curious than anything with the optimisation, it's not something i usually do.
     
  9. ph101

    ph101 Member

    Joined:
    Jun 20, 2016
    Posts:
    387
    Sure, I mean it's good to think about just maybe you don't need to get carried away - for sure if you wanted to use a controlling object to draw you would want to plan that well in advance (also that technique could be a real pain depending on how you use layers etc )
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice