• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Game slowing down when moving around the room, slowly returns to normal after staying still

Hello guys,

I'll try to explain my scenario.
I've been working on a game with a room that's 4000 by 4000. I don't know if that room size is overkill or not but I guess I'm trying to see what limits I can push with my game.
I modified an asset that fills the room with grass vertex buffers (grass sprites), there was no performance issues at all, wonderful asset. However my game needs the grass to disappear when certain tiles change so I went through various ways of trying to make this work. My first idea which worked well was placing many instances around the room which all independently create grass vertex buffers (sprites) inside the tile's dimensions. This worked, I was able to remove that patch of grass sprites by simply using instance_destroy(); on that instance creating grass on that tile. Eventually allowing my character to remove grass on a certain tile using a shovel. Yes I could just use tiles, but I like the dynamic appearance of using windy grass vertex buffers. Anyway it worked. However, the moment I decided to fill my room with all of these objects to have grass everywhere, my fps dropped by half, it went all slow motion and quite frankly unplayable. So I decided to blame the use of too many objects and tried to modify the asset itself.

I added a loop to the creation code for this obj_vertexgrass that creates grass sprites everywhere, and within this loop, a grid the size of the room that stores the buffer id for the grass sprites / vertex buffers in each tile. This is so that I can make the draw event only draw grass sprites on certain tiles, throughouy the entire room. This method also came with a giant performance impact, perhaps worse than just using objects, but further tweaking the draw event to strictly only draw sprites from the grid that are inside the camera's view fixed everything! - or so I thought. I began joyfully running to the bottom right of the room to make sure my code drew grass on all tiles along the x and y axis, and noticed the game getting progressively slower and slower. Player speed slowing, animation slowing, time slowing. The game is getting slower the higher the x and y coordinates are and I honestly have no idea what to do now. I don't even need to walk far to notice the game slow down.

I thought for a moment that maybe running around the room adds more sprites to the draw event, slowing it down,. So I added more code that does buffer_delete() on all grass sprites previously drawn that are now outside the camera's view, so that they get deleted from the draw event if they somehow aren't already and still the same issue. Vertex buffers are much faster to draw than objects aren't they?

I'm genuinely clueless what to do next. Any advice or ideas would be much appreciated.
 

renex

Member
i think you're overcomplicating the design here.

wouldn't it be easier to just define one grass tile vertex buffer at game start and reuse it for every grass draw? by making a separate vertex buffer for each grass tile, you're effectively nullifying the performance benefits of using vertex buffers at all.

moreover, you could add some extra logic to only draw the grass tiles currently inside the view, or deactivate grass tiles that are far away - that should give you a sizable speedup as simple bounding box checks such as those are a lot faster.

additionally, if only some of your grass tiles can be shoveled up, then you could build one big vertex buffer that has all the immutable grass tiles at once, and then only draw the ones the player can interact with separately. that's a technique i use in my games to speed up things like tiles and decorations that can't be interacted with.

as a side note, trying to do things yourself will hardly ever be faster than gm's builtin functionality, as builtin code runs way faster than custom gml solutions. let gm do most of the work for you, and you should be fine.
 
wouldn't it be easier to just define one grass tile vertex buffer at game start and reuse it for every grass draw? by making a separate vertex buffer for each grass tile, you're effectively nullifying the performance benefits of using vertex buffers at all.

moreover, you could add some extra logic to only draw the grass tiles currently inside the view, or deactivate grass tiles that are far away - that should give you a sizable speedup as simple bounding box checks such as those are a lot faster.

additionally, if only some of your grass tiles can be shoveled up, then you could build one big vertex buffer that has all the immutable grass tiles at once, and then only draw the ones the player can interact with separately. that's a technique i use in my games to speed up things like tiles and decorations that can't be interacted with.
Thanks for the response. I've tried exactly that as quoted below. I probably should've mentioned the creation is done during game start. Anyway I'm doing what you recommended but I'm completely confused as to why the game gets slower the further along the x and y axis I go. Returning to the top left of the room returns the framerate to normal. In the draw event I have a loop that draws buffers from a grid if the grass buffer is inside camera's view, and if the grass isn't inside a mountain, building or tree. Could this loop be responsible for such awful performance the further away I travel along x and y? The loop starts at camera_get_view_x and camera_get_view_y, so it's not like its looping through the entire room, just what's visible

So I decided to blame the use of too many objects and tried to modify the asset itself.

I added a loop to the creation code for this obj_vertexgrass that creates grass sprites everywhere, and within this loop, a grid the size of the room that stores the buffer id for the grass sprites / vertex buffers in each tile. This is so that I can make the draw event only draw grass sprites on certain tiles, throughouy the entire room. This method also came with a giant performance impact, perhaps worse than just using objects, but further tweaking the draw event to strictly only draw sprites from the grid that are inside the camera's view fixed everything! - or so I thought. I began joyfully running to the bottom right of the room to make sure my code drew grass on all tiles along the x and y axis, and noticed the game getting progressively slower and slower. Player speed slowing, animation slowing, time slowing. The game is getting slower the higher the x and y coordinates are and I honestly have no idea what to do now. I don't even need to walk far to notice the game slow down.
 

renex

Member
try using the debugger profiler, and see what's actually using up resources as you move down in the room. it might help you identify the real problem.
 
1612827115553.png
This is admittedly the first time i've used the debug profiler, but seeing as it's definitely the draw event I wrote in that's causing these issues, here is the code:
(i've tried to remove as much of the asset's code as possible, since it's paid for, and considering that wasn't causing any issues anyway.)
Lines 16 to 50 are where the code that started these issues is.

Code:
draw_self();
gpu_set_alphatestenable(true);
if (bugfix) gpu_set_ztestenable(true);

//Shader
if (grass_animate){
    shader_set... etc
}

// delete grass previously visible
while ds_list_empty(clear_grass) == false {
    buffer_delete(clear_grass[| 0]);
    ds_list_delete(clear_grass,0); //remove from list
}

// VARIABLES
// start drawing at camera x y:
camx = camera_get_view_x(cam);
camy = camera_get_view_y(cam);
gridx = camx;
gridy = camy;
// camera width & height:
c_width = camera_get_view_x(cam)+camera_get_view_width(cam)
c_height = camera_get_view_y(cam)+camera_get_view_height(cam)

buff = 0;
draw_done = 0;

while draw_done != 1 {
   
    tile = tilemap_get(map_id, gridx, gridy) & tile_index_mask;
   
    // get vertex buffer id from grid resembling room w*h :
    buff = 0;
    buff = ds_grid_get(ds_zgrass,gridx/8,gridy/8);
   
    if buff != 0 //and tile != 0
    and tilemap_get_at_pixel(bounds_id,gridx,gridy) != 1
    and !place_meeting(gridx,gridy, par_collision){
        vertex_submit(buff, pr_trianglelist, tex); // add to graphics (make visible)
        ds_list_add(clear_grass,buff); // add to list of grass to delete - method to try improve performance
    }
    // iterate through buffers in view:
    if gridx >= c_width and gridy >= c_height {draw_done = 1;}
    if gridx >= c_width {gridx = camera_get_view_x(cam); gridy += 8;}
    else {gridx += 8; }
   
    if camx != camera_get_view_x(cam) {draw_done = 1; }
    if camy != camera_get_view_y(cam) {draw_done = 1; }
}

//Shader
if (grass_animate){
    shader_reset();   
}

gpu_set_alphatestenable(false);
if (bugfix) gpu_set_ztestenable(false);
Yes this code isn't pristine, I'm more worried about the huge performance drop at the moment.
I just had an idea that maybe making the code only delete buffers that are definitely outside the camera's view may help, but it likely won't considering the deletion of buffers never improved anything earlier, and i'd be adding an extra loop into the draw event which I worry was the cause to start with.

Once again, any advice would be much appreciated.
 
I've been trying all week to fix this and there's definitely been no solution. I've tried dividing code between the step event and draw event since I suppose Step Events are faster at maths, maybe? Anyway, while uobserving the debug profiler, i've noticed the Step % and Ms gets extremely high when walking, the more I walk across the room the higher and hgher these get. When I minimize the game and leave it be, these values slowly drop. I've adjusted the thread title to better describe this

I feel like I may be overwhelming the shader, but that definitely can't be the case since the shader can draw probably infinite grass sprites when i'm not filtering all the grass into individual tiles. I'm starting to think that maybe the shader hates too many vertex buffer IDs being thrown at it?

If I use the same vbuff ID however, the grass would be restrcted to a set x and y, and therefore always be in the same place no matter how many I place, which is effectively useless.
I'm starting to wonder, is it even possible to achieve this, especially considering the vetrex buffer functions are very restricting in GML..?

As a result I've made a more specific thread here:
 
Last edited:
Top