#Suggestions to increase performance

14 messages · Page 1 of 1 (latest)

abstract hazel
#

Good day friends! I'm Barry (solo dev under the name Delayed Victory) and I make mining games with tile-based procedurally generated maps. I'm not a very good programmer and so I'm pretty sure the way I've coded this is not efficient. Therefore I figured I'd post my code here and ask for suggestions on how to improve this. I don't expect you to re-write it for me as I know that's not what this Discord is for, but I'm looking for suggestions on how to improve.

Before I continue, please check out the first 5 seconds of the game trailer here to get an idea of the game and what I'm trying to achieve. It's about efficiently drawing the map as seen here: https://store.steampowered.com/app/2830150/Super_Mining_Mechs/

Right now this is what I'm doing:

  1. I have a 2D array that holds all the map data. The array contains numbers that indicate what's in each tile i.e.: 0 = nothing, 1 = dirt, 2 = gold, 3 = iron, etc.
  2. Then I draw the array to the screen by looping the map array, drawing each resource tile one by one. So far so good.
  3. Then I loop through the entire map again to draw a 'shadow' tile, which is just a black square. The further away the tile is from and empty tile, the darker it gets. This is where I get extremely inefficient, and what I need help with. I've attached an image to indicate what I mean by this.
  4. I draw everything to a surface so that when the player is digging, I can subtract a sprite from this surface to basically make it seem like the player is digging into the map.

Some notes:

  • I'm already only drawing the tiles that are on-screen
  • It's possible for the player to move at such a high speed that all tiles on screen change, meaning I can't re-use parts of the previously drawn surface.
  • The game has online multiplayer so any tile on screen can change at any point (not just the center).

This message is too long to post, so I'm continuing in the comments.

#

I currently use the code below to figure out the nearest tile that emits light. It loops through all the tiles on screen, and then for each tile it checks all tiles in a 5-tile radius to see if they emit light. The closer the light source is, the less alpha the shadow tile gets. I'm sure this is quite inefficient, as this means that for each tile on screen, it has to check an additional 25 (5x5) tiles to check for a light source.

Any suggestions on how to do this more efficiently would be greatly appreciated! If you need more info I'd be happy to share it.

Thanks in advance 🙂
-Barry

#

``surface_set_target(surface[0]);
for (_yy = _tile_y; _yy <= _tile_y + _tile_h; _yy ++)
{
for (_xx = _tile_x; _xx <= _tile_x + _tile_w; _xx ++)
{
_range = 0;
_light = false;

    repeat (5)
    {
        _nn_min = _xx - (_range + 1);
        _nn_max = _xx + (_range + 1);
        _mm_min = _yy - (_range + 1);
        _mm_max = _yy + (_range + 1);

        //Using a double loop to only check outer edge of a grid range
        //Top to bottom
        for (var _mm = _mm_min; _mm <= _mm_max; _mm ++)
        {
            _res = map_array[_nn_min][_mm];
            if (resource_data[_res].light == true) 
            {
                _light = true;
                break;
            }

            _res = map_array[_nn_max][_mm];
            if (resource_data[_res].light == true) 
            {
                _light = true;
                break;
            }
        }
                
        //Left to right
        for (var _nn = _nn_min + 1; _nn <= _nn_max - 1; _nn ++)
        {
            _res = map_array[_nn][_mm_min];
            if (resource_data[_res].light == true) 
            {
                _light = true;
                break;
            }
                
            _res = map_array[_nn][_mm_max];
            if (resource_data[_res].light == true) 
            {
                _light = true;
                break;
            }
                
        }
            
        //Break if light
        if (_light) break;
                
        _range ++;
    }
                
    _alpha = 0.2 + (_range * 0.1);
    draw_sprite_ext(spr_resource_dirt_shadow, 0, _xx * 48 - _surface_x, _yy * 48 - _surface_y, 1, 1, 0, c_black, _alpha);
}

}
surface_reset_target();``

twilit elbow
# abstract hazel I currently use the code below to figure out the nearest tile that emits light. ...

Heya fellow eastasiasoft dev UmU

So if I understand the problem correctly, what I would see myself doing is, since you're using an array to hold the data of the tiles already, you could have the array indexes be the tile id, and have it hold hold structs, so you not only hold the tile type (0 = nothing, 1 = dirt, 2 = gold, 3 = iron) but also its light status, which can be from 0-4 or something (bright to dark), as well as hold the tile id's of the tiles around it.

By pre-populating this data in the array with the tile id's, this means that when a player interacts with a tile, you already know the tiles around that tile, and can directly access them to change their light status, rather than having to search hundreds or thousands of times.

This is just an idea though, since I'm not 100% sure on how your game and system works, but having more memory usage with structs is far better than bogging down the game with so many loops eating up processing power and lagging the game.

#

you could even make a function that calculates the tile id's of the surrounding tiles using the length and width of the grid, to pre-populate the array with tile id's

#

so essentially a struct like this per array index; say this tile is in index 15 of the array:

grid_array =
[
  { //one of the structs in the array
    type : 0, //(nothing)
    light : 0, //light status of the tile
    left_tile : 14, //tile id of the tile to the left of this one
    right_tile : 16, //tile id of the tile to the right of this one
    up_tile : -1, //if on the surface, doesn't exist so -1 could be     default nothing value
    down_tile : 42 //some random tile id number for the tile below this, totally depends on length and width of the grid
  }
]

could also just make left, right, up and down an array of tile id's to check:

{ //one of the structs in the array
   type : 0, //(nothing)
   light : 0, //light status of the tile
   neighbors : [14,16,-1,42]
}
#

so then you would just access the neighbor id's like:

grid_array[14].light

and update their status etc

#

this is assuming of course, you know what array index the players are destroying

elfin bobcat
#

What about using gamemaker's tilemaps to draw the tiles and just looping through and drawing black squares of varying opacity for the lights

abstract hazel
# twilit elbow so essentially a struct like this per array index; say this tile is in index 15 ...

Heyo! 👋🏻

Thanks for the suggestion! This could work, however I'm trying to minimize data in the map array because it's synced over the network. Your suggestion would heavily increase its size from one number to a struct full of data. However, it's indeed possible to have a light_array that's in sync with the map_array that just holds all the light data and is updated when the map changes.

Still this would require updating 100 tiles each time a player digs one tile, as every change affects a radius of 5 tiles around a light source, not just the tiles directly around it. (So 10x10=100 tiles). For each of these 100 tiles I'd have to check if this new light source is closer than the one they already held, and if so, update it. I could even divide the 100 tiles over multiple frames. Definitely an improvement from doing this each frame!

abstract hazel
elfin bobcat
#

Ah

twilit elbow