GML creating lists trough a script (Programming challenge)

Carloskhard

Member
In context, in my game SIDERAL there're planets that are created procedurally.I've already code so the planets have variables which state how many of each thing they have inside (diferent types of terrains, buildings, objects...) : For example a desert planet could have a few sand mountains, some cactus and maybe an oasis.

At the time of creating those objects I'm doing this:
Code:
///At create event of planets
for (i=0; i < OBJ_amount; i ++){
OBJ_pos_angularf[i]= random(360);  //The position in the planet is measured in angles
OBJ_img[i]=irandom(NUMBER);
OBJ_scale[i] = random_range(RANGE);
OBJ_orientation[i] = choose (1,-1); //To flip X axis
OBJ[i] = instance_create(x,y,OBJECT);
if (instance_exists(OBJ[i])){   //security check
    OBJ[i].image_index = OBJ_img[i];
    OBJ[i].image_xscale = (image_xscale*OBJ_scale[i])*OBJ_orientation[i];
    OBJ[i].image_yscale = image_yscale*OBJ_scale[i];
    }
}
Where OBJ would be changed with a name for THAT especific object (for example, for a dust mountain it would be:
Code:
for (i=0; i < sand_mountain_amount; i ++){
sand_mountain_pos_angularf[i]= random(360);  //The position in the planet is measured in angles
sand_mountain_img[i]=irandom(NUMBER);
sand_mountain_scale[i] = random_range(RANGE);
sand_mountain_orientation[i] = choose (1,-1); //To flip X axis
sand_mountain[i] = instance_create(x,y,OBJECT);
if (instance_exists(OBJ[i])){   //security check
    sand_mountain[i].image_index = sand_mountain_img[i];
    sand_mountain[i].image_xscale = (image_xscale*sand_mountain_scale[i])*sand_mountain_orientation[i];
    sand_mountain[i].image_yscale = image_yscale*sand_mountain_scale[i];
    }
}
*All this code is executed at each planet at create event, so each planet have it's own list of objects with all the propities that are needed. Some of these propities will be use and change later at step event ;mostly; for changing the angular position of each object so they seem to be "attached" to the planet, spinning at the same rotation.(Check the SIDERAL post to see some examples).So; as you see having some way to store and acces dinamically information for each object in each planet and some propeties of each one is 100% necesarry.

With just a few objects to spawn in planets I was dealing just fine with this, but to make this code expandable I need to make all that code (which is not long) fit in a Script which would ask for the object type and the quantity to create(maybe more stuff in the future,but for now just that), so all the code above would be executed in a script which should look something like this:
Code:
create_attached_phy(object,quantity);
So, the question and challenge now is:

HOW THE HECK DO I EVEN DO THIS?

jajaja This is exiting but I've been thinking about this and I haven't found a solution yet, so I hope some of you could help me!

So far I've considered two posible paths:

-Find a way to alter the name of a variable, for example:

Code:
//At planet create event
create_attached_phy(obj_sand_dune,sand_dune,5);

//MISTERIOUS SCRIPT CODE
///create_attached_phy(object,name,quantity);
for (i=0; i < argument[2]; i ++){
"argument[1]"[1] = instance_create(x,y,argument[0]);
....
And then I should be able to have a list of variables called "sand_dune[0],sand_dune[1],...,sand_dune[4]"

-Find another way to store this propities.
 

FrostyCat

Redemption Seeker
Ever heard of a return value?
Code:
sand_dunes = create_attached_phy(obj_sand_dune, 5);
Code:
///create_attached_phy(object, quantity)
var insts = array_create(argument1);
for (var i = 0; i < argument1; i++) {
  insts[i] = instance_create(x, y, argument0);
}
return insts;
 

Carloskhard

Member
Ever heard of a return value?
Code:
sand_dunes = create_attached_phy(obj_sand_dune, 5);
Code:
///create_attached_phy(object, quantity)
var insts = array_create(argument1);
for (var i = 0; i < argument1; i++) {
  insts[i] = instance_create(x, y, argument0);
}
return insts;
First of all thanks for answering!
I didn't find any function called array_create, I guess you meant ds_list_create, right?
I didn't thought doing it with return, cool idea! However that code will return a list for that object just as the one I have right now does(no need to use return since the script is run in the planet object, so every variable created gets stored already in that object),so it will still overlap names. I mean, if you use that script just once is cool, but second time you use (for example: create_attached_phy (obj_cactus, 5)) the new list will be named the same way as the previous(Since the list would always be called "insts"), so it will overwrite it and loose all data.

The idea is making a script that returns a diferent list for each object, so we can later acces information for each object, for example for accesing the angular position of a dune we could have "dune_sand_pos_angular[3]" .
 
Last edited:

FrostyCat

Redemption Seeker
I didn't find any function called array_create, I guess you meant ds_list_create, right?
If you don't have a function called array_create(), then your version of GM is way past its prime. You should not expect support for outdated versions of GM in a mainstream forum, especially without stating your version number.

If you want it in list form, that's fine, but it would be populated differently:
Code:
///create_attached_phy(object, quantity)
var insts = ds_list_create();
repeat (argument1) {
  ds_list_add(insts, instance_create(x, y, argument0));
}
return insts;
However that code will return a list for that object just as the one I have right now does(no need to use return since the script is run in the planet object, so every variable created gets stored already in that object),so it will still overlap names. I mean, if you use that script just once is cool, but second time you use (for example: create_attached_phy (obj_cactus, 5)) the new list will be named the same way as the previous(Since the list would always be called "insts"), so it will overwrite it and loose all data.
Your understanding of variable scoping in GML is completely messed up if you think that's happening. There is no conflict because I explicitly used var, which designates a local variable. Read the Manual's entry on it:
The Manual said:
A local variable is one that we create for a specific event only and then discard when the event has finished (the only exception to this is in the script resources, where a var declared variable is local to the script and then discarded).
The insts from the first call is thus NOT the same as the insts from any subsequent call. Normally the value would have been discarded after the script is done, but using it in return allows the value to be transferred out.
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
I didn't find any function called array_create, I guess you meant ds_list_create, right?
That's weird... could you please tell us what version you are on currently? That function definitely exists, I use it regularly...
 

Carloskhard

Member
That's weird... could you please tell us what version you are on currently? That function definitely exists, I use it regularly...
If you don't have a function called array_create(), then your version of GM is way past its prime. You should not expect support for outdated versions of GM in a mainstream forum, especially without stating your version number.

If you want it in list form, that's fine, but it would be populated differently:
Code:
///create_attached_phy(object, quantity)
var insts = ds_list_create();
repeat (argument1) {
  ds_list_add(insts, instance_create(x, y, argument0));
}
return insts;

Your understanding of variable scoping in GML is completely messed up if you think that's happening. There is no conflict because I explicitly used var, which designates a local variable. Read the Manual's entry on it:

The insts from the first call is thus NOT the same as the insts from any subsequent call. Normally the value would have been discarded after the script is done, but using it in return allows the value to be transferred out.
Okay I was wrong with that function, I wasn't searching for it right.And I'm using last version of GM 1 (1.4.9999).

I understand what var are, what I meant is that your code returns a SINGLE long array with ALL objects in the SAME array, so if I want to access the number of an object in a planet with 20 diferent kind of objects I would have to make multiples counts to see where that object is, which maybe is not the best way. For example, if I had 4 cactus,1 oasis,10 rocks and 3 mountains (created in that order), to access mountain 2 I would have to count how many other objects were created before that (in this case 16), so mountain number 2 would be "insts[17]". I don't know how hard or easy can be to do that dinamically, especially if you consider some planets can have up to 15 diferent kind of objetcs.I'll try that today and see how it turns out!

(I hope I'm expressing myself clearly enough, I'm not native english so sorry if I'm not explain this the best way).


In the other hand,what I've been able to come up since yesterday is creating a list for every object and call it as an array of lists
Code:
///create_attached(obj,quantity);
var obj,quantity,obj_attached,i;
obj = argument[0];
quantity = argument[1];
lista[obj] = ds_list_create();
for (i=0; i < quantity; i = i+1){
    obj_attached[i] = instance_create(x,y,obj);
    ds_list_add(lista[obj],obj_attached[i]);
    //set variables for obj_attached[i]
This way, when I need to acces the id of an object in the step event I can use:
Code:
///Inside step event:
for (i=0; i<quantity; i+=1){
    obj_attach_step(obj_attached)
}
//Inside obj_attach_step()
var obj_attach;
obj_attach = ds_list_find_value(lista[argument[0]],i);
if (instance_exists(obj_attach) and obj_attach != undefined){
    obj_attach.x = x + lengthdir_x(radioDist,obj_attach.pos_angular + image_angle);
    obj_attach.y = y + lengthdir_y(radioDist,obj_attach.pos_angular + image_angle);
    angle = point_direction (x,y,obj_attach.x,obj_attach.y);
    obj_attach.image_angle = angle + 90;
}
This seem to work for now...but there's another problem now (When you solve one problem another one pop up,classic programming cycle jaja).If I run this code at draw event it seems to work, but if I run it on step event it doesn't, it just runs on the first object on the list while the same script at draw event runs for every object as it should.
Furthermore, if I delete the security check "and obj_attach != undefined" the debug tab shows that obj_attach is undefined...
*There is another little problem.In "create attached" script:
Code:
///create_attached(obj,cantidad,scale);
var obj,cantidad,i,obj_attached,img,scale,orientation,pos_angular,at_scale;
obj = argument[0];
cantidad = argument[1];
if(argument_count > 2)scale = argument[2];
else scale = 1;
lista[obj] = ds_list_create();
for (i=0; i < cantidad; i = i+1){
    obj_attached[i] = instance_create(x,y,obj);
    ds_list_add(lista[obj],obj_attached[i]);
    with(obj_attached[i]){
        img=irandom(5);
        orientation = choose (1,-1);
        pos_angular = random(360);             //This doesn't work,it doesn't passes the variable right
        image_index = img;
        image_xscale = scale;              //This works
        image_yscale = scale;
    }
    obj_attached[i].pos_angular = random(360); //This works and passes the variable right
}
I don't know why it doesn't work passing variables through "with" but it does with "x.pos_angular"...at least I can get around this, but with the other problem I'm totally loss right now
 
Last edited:

Carloskhard

Member
Some people suggested me to use this code inside the script and I think it can be useful:
Code:
variable_instance_set(id, object_type+"_color",c_white);
 
Top