DS_LIST Scope

C

Cable_Guy

Guest
Hello everyone,

I've been searching for some info regarding variable scope for DS Lists. I'm sort of under the impression they are global.

My scenario is that I have a number of instances in a room that are from the same object. I am setting them up so that they monitor a circle around themselves for enemy instances. To accomplish this, I have a script that can be called by any instance that will populate a list of enemy instances within its radius. My plan was to have the script update the calling-instance with a DS List of all enemy objects.

Since my script is using collision_circle_list, it will populate a DS List created in the script of all instances in a radius of itself. Then it will filter the list down to objects that are 'enemies', sorted by nearest to furthest, and then pass that back to the calling instance. If an object creates a DS List, is it local to that object only , or is it global?

I can make the script do all of its stuff, and then pass an array back out instead, then destroy the DS List before the script ends. If Lists are global then I would image it will get messy when multiple instances are accessing the same list.

Any direction on this is very much appreciated. Thanks!
 
I've been searching for some info regarding variable scope for DS Lists. I'm sort of under the impression they are global.
It all depends on how you define/create them.
This ds_list is local to the event/script:
Code:
var thisList = ds_list_create();
This ds_list is an instance variable (exists in the object instance):
Code:
thisList = ds_list_create();
This ds_list would be global:
Code:
global.thisList = ds_list_create();
It is entirely up to you how you want to define them.
 
DS Lists are global. When you create a ds_list using ds_list_create, it returns an id that you can use to manipulate that list using the other ds_list functions.

If an instance creates a list:

Code:
my_list = ds_list_create()
then my_list holds the id of that list. If it's the first list you created in the game, id will be 0.

If you want other instances to be able to share that list, you would just pass the value of my_list to another instance, OR, if this is a list that is going to be truly global and used throughout the game by a lot of instances(and not destroyed till the end of the game for example), you could create the list at the start of the game somewhere:

Code:
global.enemy_list = ds_list_create()
Now, all instances can reference that list just by using global.enemy_list.

For your usage example, it would work for your script to create and return a ds_list id to the instance that requires it, as long as you then have the instance destroy the list when it is no longer in use by that instance.

I would pass in the calling instance id, because then you can use that instances x and y coordinates to run the collision_circle_list function.
// Script to find enemies
Code:
var _calling_instance = argument0;
var _radius = argument1;
var _object_to_check_for = argument2;

var _enemy_list = ds_list_create();

// collision_circle_list(x1, y1, rad, obj, prec, notme, list, ordered);
var _num_enemies_found = collision_circle_list(_calling_instance.x, _calling_instance.y, _radius, _object_to_check_for, false, true, _enemy_list, true);

if ( _num_enemies_found == 0 )
{
    ds_list_destroy(_enemy_list)
    // instance will need to check return value from this function.
    // By returning "noone", this indicates no enemies were found.
    _enemy_list = noone;
}

// return the newly created enemy list id (or noone if no enemies were found) that contains
// the enemies found to the instance that called this function.
return _enemy_list
Now if the instance that calls this script receives and valid id in return (not noone), it now has the responsibility for destroying this list, so take care to manage that part carefully.

In @BaBiA Game Studio 's example above:

Code:
var thisList = ds_list_create();
thisList is indeed a local variable and will go out of scope after the script/event ends. HOWEVER, the ds_list that was created by this code will still exist globally, and you will have lost track of the id of the list (it was contained in the variable thisList, which would have been lost after the script ends).

This will cause a memory leak.

You must take care to either destroy such a list by the end of the script, or save its id somewhere or it will be floating around in memory till the end of the game.
 
C

Cable_Guy

Guest
@IndianaBones - The script I have so far is actually very close to your example. Each instance that calls the script will have its own list of enemy objects populated by the script it calls. In this case I don't need them to share a common list of enemies.

I guess that brings me to another question. When I pass the list back to the calling instance, should I put it in an array within that instance, or keep it as a ds_list within that instance? Once the instance has a list of enemies, I may have it decide for itself which it should attack based on whatever parameters, one of which is the way it is sorted from nearest to furthest. The instance is always receiving a new copy of the list at every step, so if an enemy dies or moves out of range the list will update accordingly, without having to actually use code to add or remove items from it. The instance has a variable for storing the list of enemy ids, and when the script is called, the script clears that variable out, then checks and repopulates it. Also, the script destroys the ds_lists it created as I have one for the collision_circle_list with all instances, and a second that stores the sorted enemy instances.
 
Unless there is a reason you need to transfer/save the data to an array, I see no need to do that. You're updating the list every step anyway. The overhead cost of copying the list to an array every step is something I would avoid if possible.
 
H

Homunculus

Guest
Instead of creating and destroying a ds_list every step (you are destroying them, right?), why not create one in the create event of the object and pass it to the script as argument to be filled?

At the end of the step you just clear it, and in the cleanup event you can finally destroy it
 
Last edited by a moderator:

samspade

Member
This was already said, but it might be important enough to repeat.

Lists are effectively 'global' (they aren't but you won't be far off if you think of them that way). However, the variables that store the reference to the list act exactly like every other variable in GML. If the variable disappears before you destroy the list, the list continues to exists and can no longer be destroyed.

So as IndianaBones said, whenever you create a list, you need to destroy it. My personal practice is to write the destroy line immediately after writing the create line and before I write any other code using the data structure. But regardless, always track the reference to the data structure and destroy it.

Remember also that functions like ds_exists exist which is helpful if you're going to use a script that might or might not return a data structure. As you'll need to call ds_*_destroy if it does, but doing so will give you an error if it doesn't.
 
C

Cable_Guy

Guest
Hey folks,

Just wanted to drop a note of thanks for all of the information regarding ds_lists. The help files I find only scratch the surface on a lot of things, but I have definitely come away with some excellent pointers on this topic. One of the things I really like is the idea of writing the code to destroy the list at the same time the code to create it is keyed in, as suggested by @samspade. Anyway, thanks again to everyone that took the time to help shed some light on this topic!
 
Top