• 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!

GameMaker With statement and child objects

Le Slo

Member
Hello!

I've been having troubles I don't really understand with the with statement and object parenting. Here is what I have:

-An obj_laser.
-An obj_laserAttack (child object of obj_laser).

So, I need to save the positions of those objects, and for that I use the following to save the positions:
Code:
ini_open(argument[0]);

//Save the position of the lasers
with(obj_laser){
    ini_write_real("LaserX",string(number),round(x/128)*128);
    ini_write_real("LaserY",string(number),round(y/128)*128);
}
So the logical thing to do is read the positions, when loading a game, the same way:

Code:
ini_open(argument[0]);

//Place the lasers in their saved position
with(obj_laser){
    x=ini_read_real("LaserX",string(number),x);
    y=ini_read_real("LaserY",string(number),y);
}
Well somehow that doesn't work! I need to specify a with statement for the obj_laserAttack for loading correctly their positions, but Ï don't need to add it to the saving function! What is going on here?!

I had this working not so long ago, without adding the with statement for obj_laserAttack, and I've messed with a lot of the code, something must had gone wrong, so my main question will be the following:

Are there ways of "deparenting" objects through code? It is possible to mess up with the with statement?
 

CloseRange

Member
@Le Slo
you say it doesn't work but how so?
What does it do?
do none of the objects move to position?
do only laser objects move? (and not lasterAttack)
do the objects never show up?

do the laser objects actually exist when you start the game? Or are they meant to be created during gameplay?
also does 'laserAttack' have it's own create event? if so remember to add 'event_inherited();'
 

Le Slo

Member
@Le Slo
you say it doesn't work but how so?
What does it do?
do none of the objects move to position?
do only laser objects move? (and not lasterAttack)
do the objects never show up?

do the laser objects actually exist when you start the game? Or are they meant to be created during gameplay?
also does 'laserAttack' have it's own create event? if so remember to add 'event_inherited();'

Sorry. I'll detail what is happening.

-I have a room with all the obj_laser, all the obj_laserAttack and the player. They are placed in the original positions they should be.
-Obj_laserAttack has it's own create event (didn't use event_inherited(), so I copied everything and add new variables, you already taught me something! thanks!)
-During the first step, from the step player, i call the function loadGame. I use a variable to do this only once, I can see that's not very good, what alternatives do I have? I do this because I have code in every creation code. This means that every obj_laser and obj_laserAttack is already there when I call the function.

When I do not add the with(obj_laserAttack) only the obj_laser positions are load, and all the obj_laserAttack appear at their original positions.
 

CloseRange

Member
When it comes to running load once in the step event that is perfectly fine. I like to call this the post create event (honestly gm should have this event anyway)

But if it works when adding with(obj_laserAttack) then hey at least it works no need to change it but it's still odd

with is an event that is called on that object along with all its children objects
how sure are you that you actually made obj_laserAttack a child of obj_laser? Did you accedently flip it? what if you just have with(obj_laserAttack) but not with(obj_laser)
 

Le Slo

Member
Well, I've double checked the relationship between the obj_laser and the obj_laserAttack, and it's correct. I actually have other objects (obj_laserSnap & obj_laserSnapAttack) that are children of obj_laser (actually obj_laserSnapAttack is a child class of obj_laserSnap) and they work correctly! It's pretty weird, because the with(obj_laser) of the function saveGame works perfectly!

I guess you are right, at least I can make it work but this issue is bugging me, I would like to understand what is happening if I want to use it in the future. But I guess it's enough with a structure like this to avoid applying certain codes to certain objects:

Code:
with(obj_laser){
     if(object_index!=obj_laserAttack){
          //code
     }
}
 

Hyomoto

Member
You might need to look into the room start event. It takes place after everything has been created but before the first step event. If there's code during room creation that needs to be run only once, that's not a bad place for it.

However when it comes to your with statement, all children are called from the parent event. So if obj_laser is the parent of obj_laserAttack then it's going to call both. To reduce the scope to just the second group, you should be calling that group.

I'll be honest, your problem is a bit vague and I have a hunch whatever you are doing is flawed in design, not execution. However, with these two pieces of information you should be able to get a little further.
 

Le Slo

Member
You might need to look into the room start event. It takes place after everything has been created but before the first step event. If there's code during room creation that needs to be run only once, that's not a bad place for it.
That's something really useful! Definitely I'll put there my load function.

I'll be honest, your problem is a bit vague and I have a hunch whatever you are doing is flawed in design, not execution. However, with these two pieces of information you should be able to get a little further.
First, how so in design? The type of objects I have? How I handle save? Something else?

Here a super detailed explanation of my problem:

-I have two functions saveGame and LoadGame.

-The function loadGame is now called from the room creation code like this:
Code:
    if(file_exists("Save2.sav")){
            loadGame("Save2.sav");
    }
The function loadGame is:

Code:
///@description loadGame(file)

instance_activate_all();
ini_open(argument[0]);

//Place the lasers in their saved position
with(obj_laser){
    x=ini_read_real("LaserX",string(number),round(x/128)*128);
    y=ini_read_real("LaserY",string(number),round(y/128)*128);
}
//Code to load the player position
ini_close();
The function saveGame is called when I press esc, in step event of the player, and the function is like this


Code:
///@description saveGame(file)

//Activamos todos los objetos para que entren en los with
instance_activate_all();

ini_open(argument[0]);

//Save all the positions
with(obj_laser){
    ini_write_real("LaserX",string(number),round(x/128)*128);
   ini_write_real("LaserY",string(number),round(y/128)*128);
}
//Code tosave the player position

ini_close();
Here the proof that obj_laserAttack is child of obj_laser:
PArenting.PNG

And now, the example:

In this image we can see four objects:

-The circle is the obj_player.
- The red object is obj_laser.
-The green one is obj_laserAttack.
-The blue one is obj_laserSnap. (which is also a child from obj_laser)
[The colors are not the defining part of the object, but the circle or the diamond around the plus symbol]

Initial.PNG

Thats the initial position of the objects, the position they are placed in the room. I move the objects so the end like this before pressin escape (saving the game):

Saved.PNG

Then I close the game, and I open it again, now that a save file exists, it should be loaded. This is the result:
Loaded.PNG

Ignore the changing colors, what is important here is how the obj_laserAttack it's not in the saved position.

Now, without saving the game I close it. I add a with statement in the loadGame function as it follows:

Code:
///@description loadGame(file)

instance_activate_all();
ini_open(argument[0]);

//Place the lasers in their saved position
with(obj_laser){
    x=ini_read_real("LaserX",string(number),round(x/128)*128);
    y=ini_read_real("LaserY",string(number),round(y/128)*128);
}
with(obj_laserAttack){
    x=ini_read_real("LaserX",string(number),round(x/128)*128);
    y=ini_read_real("LaserY",string(number),round(y/128)*128);
}

//Code to load the player position
ini_close();
Basically the same code but changing the object inside the with. When I reopen the game this is the result:

Attack.PNG

This is proof that the saveGame function is working properly without the need of adding a specific with for the obj_laserAttack. It makes no sense this asymmetrical code between the saveGame and loadGame functions.

I hope this explanation does enlighten enough the problem I'm having.
 

Hyomoto

Member
What I've gathered from your post is you are creating a save state using an ini file that you use to set up the field. When I say the design is flawed, hey if it works, it works so go with that. But this seems like the type of system that can break pretty easily. It's relies on a very specific layout and has no error checking. I can offer a suggestion to point you in a direction and maybe that will help: something to consider is you should be expecting all the entries to be there. As in, if I read this correctly you don't have a random number of objects to save. Therefore you should expect a specific number of entries and therefore all three objects should have entries. Your first impulse to call with on obj_laser to save everything is correct, and since with is not broken that just leaves your code. The issue is clearly it's either not saving how you expect, or it's not loading how you expect and you need to figure out which. The problem with using ini files is they store everything you put in them and only overwrite old entries, it's not really making a 'fresh' save unless you delete the file first. I'd delete the save game, then look at what it creates and see if the values in there are what you want. If they are, then check the values it's loading. My suspicion is you are getting some 'default' values either purposefully, or incorrectly, and that's the source of your issue.
 

Le Slo

Member
Hmmm, interesting. Thanks for the advice. I will definitely do something with my saving system, as for now the save files don't always work after updating the room. Are text files a good approach to make save files?

Anyway, I do believe that there is something wrong with child objects at some point (maybe with objects activated), so I've made this function, which counts instances and child instances:
Code:
///@description withDebug()

//Define counters
var laser=0;
var laserAttack=0;
var laserSnap=0;
var laserSnapAttack=0;

//Activate all instances
instance_activate_all();

//Count lasers and child objects
with(obj_laser){
    if(object_index==obj_laser){
        laser+=1;
    }
    if(object_index==obj_laserAttack){
        laserAttack+=1;
    }
    if(object_index==obj_laserSnap){
        laserSnap+=1;
    }
    if(object_index==obj_laserSnapAttack){
        laserSnapAttack+=1;
    }
}

//Write first set of values
show_debug_message("---LASER---");
show_debug_message("Laser=" + string(laser));
show_debug_message("LaserAttack=" + string(laserAttack));
show_debug_message("LaseSnap=" + string(laserSnap));
show_debug_message("LaserSnapAttack=" + string(laserSnapAttack));


//Reset variable
laserAttack=0;

//Count laserAttacks
with(obj_laserAttack){
    laserAttack+=1;
}

//Write laserAttacks
show_debug_message("---LASER ATTACK---");
show_debug_message("LaserAttack=" + string(laserAttack));

//Reset variables
laserSnap=0;
laserSnapAttack=0;


//Count laserSnap and childs
with(obj_laserSnap){
   if(object_index==obj_laserSnap){
       laserSnap+=1;
   }
   if(object_index==obj_laserSnapAttack){
       laserSnapAttack+=1;
   }
}

laserSnapAttack=0;

//Write laserSnap
show_debug_message("---LASER SNAP---");
show_debug_message("LaserSnap=" + string(laserSnap));
show_debug_message("LaserSnapAttack=" + string(laserSnapAttack));

//Count laserSnapAttack
with(obj_laserSnapAttack){
   laserSnapAttack+=1;
}
//Write laserSnap
show_debug_message("---LASER SNAP ATTACK---");
show_debug_message("LaserSnapAttack=" + string(laserSnapAttack));
When I call this function on the creation code of the room:

---LASER---
Laser=259
LaserAttack=123
LaseSnap=85
LaserSnapAttack=8
---LASER ATTACK---
LaserAttack=123
---LASER SNAP---
LaserSnap=85
LaserSnapAttack=8
---LASER SNAP ATTACK---
LaserSnapAttack=8

As you can see, here are all the objects perfectly counted.

When I call this function on the event step of the player like this:

Code:
if(debug==0){
    withDebug();
    debug=room_speed;
}
else{
    debug-=1; 
}
The first time the function prints the debug, we can see no link between parent and child.

---LASER---
Laser=259
LaserAttack=0
LaseSnap=0
LaserSnapAttack=0
---LASER ATTACK---
LaserAttack=123
---LASER SNAP---
LaserSnap=85
LaserSnapAttack=0
---LASER SNAP ATTACK---
LaserSnapAttack=8

Then the second time, we've got a glimpse of some childs:

---LASER---
Laser=259
LaserAttack=23
LaseSnap=0
LaserSnapAttack=0
---LASER ATTACK---
LaserAttack=123
---LASER SNAP---
LaserSnap=85
LaserSnapAttack=0
---LASER SNAP ATTACK---
LaserSnapAttack=8

Those 23 LaserAttack that appear, I think they may be the lasers around the position of the player(the ones that are activated). If it is an issue with activation, I don't really understand why the instance_activate_all() doesn't work.
 
Last edited:
Top