Papa Doge
Member
Hello,
I'm woking on a feature where trees left unchecked grow into a massive forrest. I have two working versions right now but both have performance issues once I get to around 100 trees.
I need some advice on how to fix one of my versions or something new to try.
/* ------------------------------------------------- */
VERSION 1
Description:
Each tree object has a variable called "seeding", that when true initiates a FOR loop that checks the 4x4 space around the tree looking for an available 32x32 cell to drop a single seed. If a cell is found, it is added to a ds_stack where a separate object does the work of planting each seed using a LIFO queue.
/* ------------------------------------------------- */
VERSION 2
Description:
Each tree object has a variable called "seeding", that when true accesses a local "count" variable that starts in cell position 0 (top left) and checks to see if a seed can be placed in that location. If that space is available, the coords are added to a ds_stack where a separate object does the work of planting each seed using an LIFO queue. If there is no space, the tree waits for the next germination to begin and then checks cell 1 and so on until a space is found.
/* ------------------------------------------------- */
FULL SET OF CODE
obj_germinator:
Contains all my timers for when trees should seed and grow
CREATE EVENT
STEP EVENT
obj_tree:
The individual instances of trees in the room that wait until the germinator says it's time to seed and then perform their seeding check.
scr_seeding_check version 1:
scr_seeding_check version 2:
scr_tile_check_germination:
This little script is checking the specific attributes of the tile our tree wants to drop a seed in. Trees need to be planted on grass/dirt and cannot grow on top of other kinds of grounded objects like the ones in the list. This simply returns true or false if a seed can go here.
/* ------------------------------------------------- */
Version 2's results are quite bad. I could make it better but selecting a cell at random to check instead of moving through the 4x4 space serially, but that still won't fix my performance issues. I had assumed that the FOR loop in version 1 was the culprit, but even with that loop removed in version 2 I still see significant hang when I have a lot of trees doing checks at once.
I was hoping my stack approach would fix this but it seems the issue is somewhere else and I'm having a hard time wrapping my head around the problem space and honestly my code at this point.
As always, any and all help is greatly appreciated.
I'm woking on a feature where trees left unchecked grow into a massive forrest. I have two working versions right now but both have performance issues once I get to around 100 trees.
I need some advice on how to fix one of my versions or something new to try.
/* ------------------------------------------------- */
VERSION 1
Description:
Each tree object has a variable called "seeding", that when true initiates a FOR loop that checks the 4x4 space around the tree looking for an available 32x32 cell to drop a single seed. If a cell is found, it is added to a ds_stack where a separate object does the work of planting each seed using a LIFO queue.
/* ------------------------------------------------- */
VERSION 2
Description:
Each tree object has a variable called "seeding", that when true accesses a local "count" variable that starts in cell position 0 (top left) and checks to see if a seed can be placed in that location. If that space is available, the coords are added to a ds_stack where a separate object does the work of planting each seed using an LIFO queue. If there is no space, the tree waits for the next germination to begin and then checks cell 1 and so on until a space is found.
/* ------------------------------------------------- */
FULL SET OF CODE
obj_germinator:
Contains all my timers for when trees should seed and grow
CREATE EVENT
Code:
/// @description
/* -------------------- */
// Debugging
debugging = false;
// Germination
time_germinating = 0;
time_to_germinate = 540;
growth_rate = 1;
// Sprouting
time_sprouting = 0;
time_to_sprout = 320;
sprout_rate = 1;
// Seeding
ds_stack_seeds = ds_stack_create();
Code:
/// @description
/* -------------------- */
#region Germinating
/* -------------------- */
scr_debugging("Time germinating is " + string(time_germinating));
time_germinating = APPROACH(time_germinating, time_to_germinate, growth_rate);
if (time_germinating == time_to_germinate) {
time_germinating = 0;
with (obj_tree) {
if (obj_tree.sprouting == false) {
seeding = true;
}
}
}
/* -------------------- */
#endregion
/* -------------------- */
/* -------------------- */
#region Sprouting
/* -------------------- */
time_sprouting = APPROACH(time_sprouting, time_to_sprout, sprout_rate);
if (time_sprouting == time_to_sprout) {
with(obj_tree) {
if (sprouting == true) {
stage++;
}
}
time_sprouting = 0;
}
/* -------------------- */
#endregion
/* -------------------- */
/* -------------------- */
#region Seeding
/* -------------------- */
if (ds_exists(ds_stack_seeds, ds_type_stack)) {
if (ds_stack_size(ds_stack_seeds) > 0) {
var seed_coordinates = ds_stack_pop(ds_stack_seeds);
var seed_x = seed_coordinates[0];
var seed_y = seed_coordinates[1];
instance_create_depth(seed_x, seed_y, -seed_y, obj_tree);
}
}
The individual instances of trees in the room that wait until the germinator says it's time to seed and then perform their seeding check.
Code:
/* -------------------- */
#region Seeding
/* -------------------- */
if (seeding == true) {
scr_debugging("Trying to drop seeds here...");
scr_seeding_check();
seeding = false;
}
/* -------------------- */
#endregion
/* -------------------- */
Code:
// Add available space as cell coordinates in a temp table
var ds_list_spaces = ds_list_create();
var xx = x1;
var yy = y1;
var free_space;
var count = 0;
for (var i=0; i<(rows*columns); i++) {
free_space = scr_tile_check_germination(xx, yy);
if (free_space == true) {
ds_list_spaces[| count] = [xx, yy];
count++;
show_debug_message("Adding to the list position " + string(i));
} else {
show_debug_message("Something in the way at position " + string(i));
}
xx += cell_size;
if (xx == x2) {
xx = x1;
yy += cell_size;
}
}
// Randomly select one of the cells and place a single seed
//var num_spaces = ds_list_size(ds_list_spaces);
if (count > 0) {
var lifo_queue = obj_germinator.ds_stack_seeds;
var random_space = floor(clamp(random(count), 0, count - 1));
show_debug_message("Number of spaces is " + string(count) + " and random space set to " + string(random_space));
var seed_coords = ds_list_spaces[| random_space];
ds_stack_push(lifo_queue, seed_coords);
}
// Destroy the list to free u memory
ds_list_destroy(ds_list_spaces);[/B]
Code:
// Check current position for avaiable space
var free_space;
free_space = scr_tile_check_germination(xx, yy);
// If we can seed here add these coords to the germinator's stack
if (free_space == true) {
var seed_coords = [xx, yy];
var lifo_queue = obj_germinator.ds_stack_seeds;
ds_stack_push(lifo_queue, seed_coords);
show_debug_message("Added seed coords to the stack");
} else {
show_debug_message("Something in the way at position " + string(count));
}
// Increment the seeding position and count
xx += cell_size;
count++;
if (xx == x2) {
xx = x1;
yy += cell_size;
}
if (count == count_max) {
count = 0;
xx = x1;
yy = y1;
}
[/B]
scr_tile_check_germination:
This little script is checking the specific attributes of the tile our tree wants to drop a seed in. Trees need to be planted on grass/dirt and cannot grow on top of other kinds of grounded objects like the ones in the list. This simply returns true or false if a seed can go here.
Code:
/// @ desc scr_tile_check_germination(x,y)
/// @arg x
/// @arg y
// Script that takes a specific point in the game grid and
// returns true if it has avaiable space for a tree to grow
// and false if it does not.
// CREATE REFERENCES FOR TILE DATA
var layer_grass_and_dirt = layer_get_id("Terrain_land");
var map_grass_and_dirt = layer_tilemap_get_id(layer_grass_and_dirt);
var layer_rocks = layer_get_id("Terrain_rocks");
var map_rocks = layer_tilemap_get_id(layer_rocks);
var layer_water = layer_get_id("Terrain_water");
var map_water = layer_tilemap_get_id(layer_water);
var layer_mountains = layer_get_id("Terrain_mountains");
var map_mountains = layer_tilemap_get_id(layer_mountains);
// STRUCTURES AND OBSTANCLES TO CHECK FOR
var has_structure = position_meeting(argument0+cell_size/2,argument1+cell_size/2,obj_structures_parent);
var has_enemy = position_meeting(argument0+cell_size/2,argument1+cell_size/2,obj_enemy_parent);
var has_soil = position_meeting(argument0+cell_size/2,argument1+cell_size/2,obj_soil);
var has_portal = position_meeting(argument0+cell_size/2,argument1+cell_size/2,obj_portal);
var has_player = place_meeting(argument0+cell_size/2,argument1+cell_size/2,obj_player_parent);
var has_barrier = position_meeting(argument0+cell_size/2,argument1+cell_size/2,obj_barriers_parent);
var has_sentry = position_meeting(argument0+cell_size/2,argument1+cell_size/2,obj_sentry_parent);
var has_environment = position_meeting(argument0+cell_size/2,argument1+cell_size/2,obj_environment_parent);
// PERFORM THE CHECKS
var origin_seedable = tilemap_get_at_pixel(map_grass_and_dirt,argument0,argument1);
var origin_unseedable = tilemap_get_at_pixel(map_rocks,argument0,argument1)
+ tilemap_get_at_pixel(map_water,argument0,argument1)
+ tilemap_get_at_pixel(map_mountains,argument0,argument1)
+ has_structure
+ has_enemy
+ has_soil
+ has_portal
+ has_player
+ has_barrier
+ has_sentry
+ has_environment
;
// If there is anything in this cell that would prevent us from building...
var seedable_tile;
if (origin_seedable != 0) && (origin_unseedable == 0) {
seedable_tile = true;
} else {
seedable_tile = false;
}
// RETURN THE RESULTS
return seedable_tile;
Version 2's results are quite bad. I could make it better but selecting a cell at random to check instead of moving through the 4x4 space serially, but that still won't fix my performance issues. I had assumed that the FOR loop in version 1 was the culprit, but even with that loop removed in version 2 I still see significant hang when I have a lot of trees doing checks at once.
I was hoping my stack approach would fix this but it seems the issue is somewhere else and I'm having a hard time wrapping my head around the problem space and honestly my code at this point.
As always, any and all help is greatly appreciated.