Optimizing drawing a grid

Hello everyone! I have a relatively simple issue. I'm currently creating a rts style game, and I have a "Fog of War" which is stored in a grid. It works fine currently, however I'm having a major issue with the lag. Drawing the fog on screen is pretty simple, I just have to draw the few squares of the grid that the player can currently see, but my problem is the minimap. The minimap is drawing the entire fog grid over the map sprite, which drops the game about 60 frames lower on my pc (Originally it was running at around 100). When I disable the fog the performance gets significantly better, so I know this is the issue. My current method for drawing it is simple, I just use a for loop to draw every square over the minimap, but I feel like there's got to be a better more performance forgiving way to do this?
Here's my current code if needed:
Please excuse my sloppy code
Code:
if(sprite_exists(Island_Sprite)) {
var Draw_MapX = Width-GUI_MinimapScale;
var Draw_MapY = YY+2
draw_set_alpha(1)
draw_sprite_stretched(Island_WaterSprite,0,Draw_MapX,Draw_MapY,GUI_MinimapScale,GUI_MinimapScale)
draw_sprite_stretched(Island_Sprite,0,Draw_MapX,Draw_MapY,GUI_MinimapScale,GUI_MinimapScale)
var Tx = 0
var Ty = 0
var TileScale = GUI_MinimapScale/ds_grid_width(Player_FogOfWar)
var TileScaleV = GUI_MinimapScale/ds_grid_height(Player_FogOfWar)
draw_set_color(c_black)
var alph = 1
var PrevAlph = 0
for(var i=0;i<ds_grid_width(Player_FogOfWar)*ds_grid_height(Player_FogOfWar);i+=1) {
if(ds_grid_get(Player_FogOfWar,Tx,Ty) != undefined) { alph = 1-ds_grid_get(Player_FogOfWar,Tx,Ty) }
if(alph != 0) {
if(alph != PrevAlph) { draw_set_alpha(alph) PrevAlph = alph }
draw_rectangle(Draw_MapX+TileScale*Tx,Draw_MapY+TileScaleV*Ty,Draw_MapX+TileScale*Tx-1,Draw_MapY+TileScaleV*Ty-1,0)
}
Tx += 1 if(Tx >= ds_grid_width(Player_FogOfWar)) { Tx = 0 Ty += 1}
}
I've thought about skipping tiles, as in drawing one square for every four squares, because the minimap is small enough to where each tile would not be noticed. However, I wasn't sure if that would be the best method, or even how I should go about programming that. Any help is appreciated, thanks in advance!
 

Simon Gust

Member
I suggest not drawing primitives and having to change color in the middle of drawing them. Instead I would use a black sprite and drawing it with draw_sprite_ext().
Something like this?
Code:
if (sprite_exists(Island_Sprite)) 
{
    var Draw_MapX = Width-GUI_MinimapScale;
    var Draw_MapY = YY + 2;
   
    draw_set_alpha(1);
    draw_sprite_stretched(Island_WaterSprite,0,Draw_MapX,Draw_MapY,GUI_MinimapScale,GUI_MinimapScale);
    draw_sprite_stretched(Island_Sprite,0,Draw_MapX,Draw_MapY,GUI_MinimapScale,GUI_MinimapScale);
   
    var wdt = ds_grid_width(Player_FogOfWar);
    var hgt = ds_grid_height(Player_FogOfWar);
    var TileScaleH = GUI_MinimapScale / wdt;
    var TileScaleV = GUI_MinimapScale / hgt;
   
    draw_set_color(c_black);

    for (var i = 0; i < wdt; i++) {
        var xx = Draw_MapX + i * TileScaleH;
    for (var j = 0; j < hgt; j++) {
        var yy = Draw_MapY + j * TileScaleV;
       
        var entry = ds_grid_get(Player_FogOfWar, i, j);
        if (entry != undefined) 
        {
            var alpha = 1 - entry;
            if (alpha != 0)
            {
                draw_sprite_ext(spr_blacktile, 0, xx, yy, 1, 1, 0, c_white, alpha);
            }
        }
    }}
}
Not sure if there is any good checking for undefined, if you have nothing in your grid it will return 0 if you did not set it to undefined previously.
If you set it to undefined indicating that there isn't anything inside the grid value, you should change that so that 0 means there is nothing.
 
I suggest not drawing primitives and having to change color in the middle of drawing them. Instead I would use a black sprite and drawing it with draw_sprite_ext().
Something like this?
Code:
if (sprite_exists(Island_Sprite))
{
    var Draw_MapX = Width-GUI_MinimapScale;
    var Draw_MapY = YY + 2;
  
    draw_set_alpha(1);
    draw_sprite_stretched(Island_WaterSprite,0,Draw_MapX,Draw_MapY,GUI_MinimapScale,GUI_MinimapScale);
    draw_sprite_stretched(Island_Sprite,0,Draw_MapX,Draw_MapY,GUI_MinimapScale,GUI_MinimapScale);
  
    var wdt = ds_grid_width(Player_FogOfWar);
    var hgt = ds_grid_height(Player_FogOfWar);
    var TileScaleH = GUI_MinimapScale / wdt;
    var TileScaleV = GUI_MinimapScale / hgt;
  
    draw_set_color(c_black);

    for (var i = 0; i < wdt; i++) {
        var xx = Draw_MapX + i * TileScaleH;
    for (var j = 0; j < hgt; j++) {
        var yy = Draw_MapY + j * TileScaleV;
      
        var entry = ds_grid_get(Player_FogOfWar, i, j);
        if (entry != undefined)
        {
            var alpha = 1 - entry;
            if (alpha != 0)
            {
                draw_sprite_ext(spr_blacktile, 0, xx, yy, 1, 1, 0, c_white, alpha);
            }
        }
    }}
}
Not sure if there is any good checking for undefined, if you have nothing in your grid it will return 0 if you did not set it to undefined previously.
If you set it to undefined indicating that there isn't anything inside the grid value, you should change that so that 0 means there is nothing.
Thank you! This works much faster! And you're right, I had the undefined check there for previous reasons but I never removed it.
 
Even more efficient, you might try the following:
  1. Create a surface equal to the size of your tile grid (i.e. 100x100 tiles)
  2. For each grid position draw a single pixel at whatever alpha (it looks like you have partial alpha cases based on your code)
  3. Draw the surface scaled at the minimap scale.
Further, you only need to draw to the minimap surface if it's changed from the previous state. This should significantly boost performance. Also, if you're drawing your minimap in a similar way, I would HIGHLY recommend you look at using a surface instead so you don't have to draw every tile each step for the minimap.
 

Simon Gust

Member
Even more efficient, you might try the following:
  1. Create a surface equal to the size of your tile grid (i.e. 100x100 tiles)
  2. For each grid position draw a single pixel at whatever alpha (it looks like you have partial alpha cases based on your code)
  3. Draw the surface scaled at the minimap scale.
Further, you only need to draw to the minimap surface if it's changed from the previous state. This should significantly boost performance. Also, if you're drawing your minimap in a similar way, I would HIGHLY recommend you look at using a surface instead so you don't have to draw every tile each step for the minimap.
If you mention drawing a single pixel, what exactly do you mean by that?
A 1x1 large sprite, or a draw_vertex_color() pixel? You may be aware that the draw_vertex() functions are deprecated and don't work the same on every device. Last time I used them
they missdrew themselves 1 pixel to the upper left, and they were limited to somewhat 1000 calls before just not drawing at all.

Only drawing strips and edits using a surface is really good.

Other than that, the alpha seems like an issue and it can't be evaded easily as draw_point_colour() does not seem to support alpha values other than having to set draw_set_alpha() which breaks the vertex batch (not a problem in GM:S 2.X). I'm thinking of just drawing a (say red) pixel and inside a shader, depending on how red the pixel is depends it's alpha value.
 
Last edited:
Top