SOLVED instance_activate/deactivate_region

trip

Member
I have a question for experienced programmers.

Iam using any like this for deactivate instances outside view.
GML:
var _x = camera_get_view_x(view_camera[0])
var _y = camera_get_view_y(view_camera[0])
instance_deactivate_region(_x, _y, view_wport[0], view_hport[0], false, true) // deactive instance outside view
instance_activate_region(_x, _y, view_wport[0], view_hport[0], true)
When I have some instances maybe <10 000.
2 000 active in view and 8 000 deactive outside view.
I can move with 60FPS without problem.
but when I have maybe 250 000 instances.
2 000 active in view and 242 000 deactive outside view.
Then I have lags and I have 30 FPS when moving.
I tried to create a smaller deactivation area when I moving down and deactivate the instance just above the outside view.
GML:
instance_deactivate_region(_x, _y-64, view_wport[0], 64, true, true)
// deactive instance inside small area
But result is same.

My question is. What happens to instances when transitioning from active to inactive state?
Does GM have anything like a DS_list with active and inactive instances? And writing 60 instances to the inactive list depends on the number of instances in that list?
Any ideas to speed up this process?
 

Simon Gust

Member
Deactivation and Activation is no free speed upgrade, every instance still has to be looked up to see if it is inside the region to be activated when they're deactivated.
There is an array of instances called instance_id that holds all active instances in the room.
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
Have you tried the other activate/deactivate options? IIRC, the region method is the slowest, so it might be worthwhile doing either:

1) Assign a parent object to all instances that you want to deactivate and then call instance_deactivate_object() instead of region.
2) Assign all instances to be activated/deactivated to a layer and use instance_deactivate_layer()

Both those options should be faster than trying to deactivate a region all the time. Another trick that I do is to only deactivate when the camera moves or only every X number of steps in an alarm. Doing a quick check to see if the camera x/y has moved is much faster than activating/deactivating every step. The other trick of using an alarm means that you are "spreading the load" as it were, and only deactivating every 3 or 5 steps rather than every step. I generally combine these two methods... So have an alarm that runs every few steps, and in the alarm check to see if the camera has changed position or moved more than a certain number of pixels and only deactivate/activate if it has.
 

trip

Member
I can't use deactivate layer and or parent object.
I check when camera move and execute activate/deactivate region only when moved more than tile size.
I can't use "spreading the load" because active region is + -4 tile then the camera view (visible edge for instances out of view)=> more instances.
Large active region (maybe +-10 tiles) => more active instances and performance impact.
I'm counting on the worst case scenario 4k resolution and moving by 1 tile every step.
Active region +-4 tile = 2720 active instances, deactivate 108 and activate 108 instances when moved
Active region +-10 tile = 4000 active instances, deactivate 130 and activate 130 instances when moved
But thank you for your ideas. It is good solution for some other projects.

I have solution maybe. Now I am working on this.
 

Simon Gust

Member
I think what you're trying to achieve is not possible in any game engine, especially at that resolution. My pc for example struggles to draw a 1920x1080 screen worth of 16x16 objects, let alone handle their step events.
Do you need objects? Or can it be just static images? maybe tiles would be better, they're automatically deactivated outside view. Or if it is really static, vertex buffers to draw chunks of the room would work even better.

One thing I was thinking of, was to have the instances deactivated at all times but save their ids in a grid. Then you could loop the grid at the camera coordinates and execute their events manually. (as long as you the id is saved, all instances variables are accessible and changeable).
If your objects do not fit on a grid, then I don't know either.
 

trip

Member
Instances are best when I want interaction with object.
I have all instance and layer sprite IDs saved in a grids with important variables for access from other rooms.
Is possible have 2720 active instances, deactivate 108 and activate 108 instances when moved. I tested this and work fine.
Problem is 248 000 inactive instances. Now I am working on remove this inactive instances.
I try to manually find the object in ds_grid to create instance when the object enters the active area, and destroy the instances outside the active area.
I have a similar problem with 250 000 layer sprites. I'm currently working on fixing both issues.
My game is 2,5D. Create all object like tiles is possible, but very difficult to program and drawing sprites ....
I dont know how use vertex buffers :/. Maybe later

My notebook have no problem with fullHD on intel graphic and 4k with Nvidia graphic. But game must be fullscreen, in window mode have problem. And I thing 970M is old graphic and after 2 year will older.
 

Simon Gust

Member
Instances are best when I want interaction with object.
I have all instance and layer sprite IDs saved in a grids with important variables for access from other rooms.
Is possible have 2720 active instances, deactivate 108 and activate 108 instances when moved. I tested this and work fine.
Problem is 248 000 inactive instances. Now I am working on remove this inactive instances.
I try to manually find the object in ds_grid to create instance when the object enters the active area, and destroy the instances outside the active area.
I have a similar problem with 250 000 layer sprites. I'm currently working on fixing both issues.
My game is 2,5D. Create all object like tiles is possible, but very difficult to program and drawing sprites ....
I dont know how use vertex buffers :/. Maybe later

My notebook have no problem with fullHD on intel graphic and 4k with Nvidia graphic. But game must be fullscreen, in window mode have problem. And I thing 970M is old graphic and after 2 year will older.
I don't think the tiles need to be objects to be interacted with, there are many ways to go around this issue. Every block or tile based game I know does not use instances (or the equivalent of it). Minecraft, Terraria, Stardew Valley.
And they have constant interaction with their tiles / blocks. They just know how to cover it up with cheeky coding techniques.
 

trip

Member
I think We misunderstood. I have some tilemap layers for ground, walls ..... I would like to use instances for object like Tree, furnace ... (drawing this sprites with tilemap is difficult)
 

Simon Gust

Member
I think We misunderstood. I have some tilemap layers for ground, walls ..... I would like to use instances for object like Tree, furnace ... (drawing this sprites with tilemap is difficult)
Ah yes ok. I have the same approach with my game actually. Where things like furnaces, torches and other interactable props are objects. I haven't really worked on a solution and I do not think there is a perfect one. There will always be slowdown. Like when you play minecraft and you have 10000 pistons that go up and down at the same time, of course it will lag, no matter how you code it. But that's what the players have to understand that there are limits, may it be one's pc or the game.

In my game, a torch occupies the same space as a tile (8x8) with a resolution of 960x540, so ~8000 instances active at once. That will obviously lag the game.
What comes to mind for deactivation is getting rid of _region() activation and instead write these instance ids to a grid where they can be looked up.

something like this?
GML:
var x1 = camera_get_x();
var y1 = camera_get_y();
var x2 = x1 + camera_get_width();
var y2 = y1 + camera_get_height();

for (var i = x1; i < x2; i++) {
for (var j = y1; j < y2; j++) {
    
    var inst = global.instance_grid[i, j]; // grid filled with noone (noone = no instance)
    if (inst != noone) {
        instance_activate_object(inst);
    }

}}
You can fiddle around with what areas went out of the camera and what areas went in to minimize instance_activate / deactivate calls.
 

muki

Member
This

GML:
instance_deactivate_region(_x, _y, view_wport[0], view_hport[0], false, true) // deactive instance outside view
Is a really bad way of doing this, in my opinion. Because you're essentially re-deactivating thousands of objects you aren't using, every step. It's just not efficient, and doing it this way might even cause more lag than you're trying to save, if your room and its density is much much larger than your view..

What I do is, on room start, deactivate all instances except control objects, and manually keep a zone of deactivation that lags behind a step (or more) and a zone of activation that follows the view in the current step. I never use "deactivate outside region" because it's just wasteful.



Pseudocode:

room create:
deactivate all instances
reactivate control objects

step:
deactivate LAST step's region
activate THIS step's region
update last step x/y values for use in next step




Doing it this way, keeping track of where your zone was in previous steps ensures you're only deactivating only the objects that were activate last step. Only a few dozens (a couple hundred in my case because my environment is really dense), instead of thousands, or tens of thousands. It's way more efficient. I got huge performance gains using this way.

Here's my script that handles most of this. Maybe it can give you ideas. Note my cull_previous variables. I call this script in my camera object.

Code:
function scr_ViewCulling(cull_width ,cull_height, cull_steps, cull_debug) {

    //cull_width : width of culling area
    //cull_height : height of culling area
    //cull_steps : update culling zone every nth frame
    //cull_debug : cull_debug

    if (global.count_cull == cull_steps) {
        instance_deactivate_region(global.cull_previous_x - (cull_width/2), global.cull_previous_y - (cull_height/2), cull_width, cull_height, true, false);

        global.cull_previous_x = x;
        global.cull_previous_y = y;
   
        instance_activate_region(x - (cull_width/2), y - (cull_height/2), cull_width, cull_height, true);
   
        //reactivate control objects
        instance_activate_object(obj_postfx);
        instance_activate_object(obj_postfx_glow);
        instance_activate_object(obj_audio);
        instance_activate_object(obj_gmlive);
        instance_activate_object(obj_LineVariable);
        instance_activate_object(obj_Player);


        //instance count debug message
        if (cull_debug == 1) {
          show_debug_message("Active instances : " + string(instance_count));
        }

        global.count_cull = 1;
    } else {
        global.count_cull += 1;
    }

}
 
Last edited:

trip

Member
I have solution.
I destroy instances on left/right edge and create instance on opposite edge and I destroy instances on up/down edge and create instance on opposite edge depend what is move direction.
That means destroy instances in 2 small area and create instances in 2 small area when there is a diagonal movement. And all object is stored in DS_grid where is objects id.
Each area is maybe 50-150 tiles depend on resolution.
Thank you
 
Top