GML [SOLVED] Assign code to just-created instance BEFORE it runs its create event?

X

XirmiX

Guest
I've found trouble doing this. It essentially boils down to having the create event code from the object be placed inside the object/script that creates it. The "with" variable does not help at all, wish it did, seems redundant otherwise.

What happens is:
Object creates an instance of another object >
new object instance runs its creation code >
object that created the instance changes its parameters

What I want to happen:
Object creates an instance of another object >
object that created the instance changes its parameters >
new object instance runs its creation code

Is this at all possible in any shape or form? I often run into this issue and it is annoying to deal with when I can't. So much code needs to be placed where I don't want it to be, and the instances being created end up not being allowed to have any creation code at all as a result.
 
R

Raul Rivera

Guest
What parameters do you want the created object to have changed by the object creating it?

I think that adding a variable to hold the new instance information, and then using instanceVar.parameter (where Var is your variable, and parameter is what you want to change) should allow you to change things like speed, or direction, or whatever else you need to adjust.
 
X

XirmiX

Guest
@YellowAfterlife I think the extra argument solution would be good may be, if it works how it's portrayed, but I'm having trouble wrapping my head around one thing:

Code:
/// instance_create_v(x, y, object, ...args)
var n = argument_count - 3; 
ct_argument = undefined;
ct_count = n;
for (var i = 0; i < n; i++) ct_argument[i] = argument[3 + i];
var r = instance_create(argument[0], argument[1], argument[2]);
ct_argument = undefined;
ct_count = undefined;
return r;
How exactly am I passing the forth argument (argument[3]) and beyond here into the created instance from this instance_create_v() script? Or how am I at least supposed to have the created instance know that ct_argument[1] is set in the script that it is being created from and take the argument? This is mentioned to be placed in the instance's Create event:

Code:
index = ct_argument[0];
But how does it get the value of ct_argument[0] without a "with()" statement?

I should stress that I'm looking to avoid globals here as well. For what I'm doing here, I need no globals to be used during the instance creation procedure.
 
Uhhh, why can't you use a global? The script that yellowafterlife provided is totally fine (they're probably a better programmer than 99.9% of the people on this board). You macro the global, then whenever you run the script, the global gets given a value, the instance grabs the value from the global, then the global doesn't matter anymore and can be used for another instance_create_v with no problems. I'm failing to see why that would be a problem, unless you specifically already have a global called global.g_ct_argument in which case, what the hell? And just change the name of the global that is being macroed. If you're concerned because people talk about not using globals sometimes, ignore them. Globals are faster to access than any other variable type and this script is a perfect example of a good use of globals. Just don't -overuse- globals (a common mistake would be making an enemy health variable global and then complaining because every enemy loses health when one does...but you're not that silly are you? ;) )
 
X

XirmiX

Guest
I really hate using globals, particularly when it's just for creating instances in ways that I want to. Would have been great if you could pass parameters to instances without using globals of any kind at all like this. The engine could have easily done this by allowing extra parameters to begin with, or some method that holds create event execution, so that an instance exists and have values be assigned to it before going forward. With a macro, that's more or less how it works, though a macro is a global. Guess it's the only way that makes sense to do it.

EDIT: looks like I have to use regular globals, macro means it's a global constant variable.
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
But how does it get the value of ct_argument[0] without a "with()" statement?
As the post explains, the macro serves as a shortcut to the global variable so that you don't have to use global.ct_argument or declare it as globalvar (which is deprecated in GMS2 and generally not a good thing to use).

So, with setup intact, ct_count = n would change a global variable's value, and then the object's Create event would be able to access that secretly-global variable without extra typing on your side.
 

Neptune

Member
Pretty much every object i create has this structure in the step event (notice it only runs one time...):
Code:
if !ini
{
    ini = true;
    switch(enum_value)
    {
        case ITEM.Seed_Tree_Spruce:
            sprite_index = s_seed_tree_spruce;
            max_minute = 200;
            grow_sound = snd_tree_grow;   
            grow_object = o_tree;
            grow_object_enum = RESOURCE.tree_spruce;
            grow_object_variant = choose(true,false);
            is_tree = true;      
        break;
    }
}
That being said, I really like to use enum values...
This kind of setup allows you to have very few objects in your resource tree, but you can create all sorts of different entities just by changing the initialization enumerated value.

This also allows all the code dealing with all forms of a particular object to be in one place, and not being passed around by scripts or other instances etc.

I have a more complex version of this, but im not gonna go into it unless someone is interested.
 
Last edited:

Ido-f

Member
I really hate using globals, particularly when it's just for creating instances in ways that I want to. Would have been great if you could pass parameters to instances without using globals of any kind at all like this. The engine could have easily done this by allowing extra parameters to begin with, or some method that holds create event execution, so that an instance exists and have values be assigned to it before going forward. With a macro, that's more or less how it works, though a macro is a global. Guess it's the only way that makes sense to do it.

EDIT: looks like I have to use regular globals, macro means it's a global constant variable.
You could also use a manager object's instance variable.
Gml is so abstracted behind the scenes to be convinient rather than efficient that I wouldn't be surprised if it didn't make any difference, but in other languages that's how you'd avoid using the global.
 
X

XirmiX

Guest
@Ido-f "manager object's instance" variable? Not sure what that implies. And well, in this case, it is counter-convenient. It is probably more efficient for me to just use a global of sorts the way it's already set, even if there was a basic way I could just use some sort of a statement, like, even when using a with statement in some form. It would be cool if the following simply executed the code within the statement before the create event is executed.

Code:
before with(instance_create(x,y,obj_something)){
    //code to execute before executing Create event of the newly created instance...

    //After this section, Create event of the created instance is run...
}
Or, in my case, even better if I could do this:
Code:
before with(instance = instance_create(x,y,obj_something)){
    //code to execute before executing Create event of the newly created instance...

    //After this section, Create event of the created instance is run...
}

return instance;
 

samspade

Member
@Ido-f "manager object's instance" variable? Not sure what that implies. And well, in this case, it is counter-convenient. It is probably more efficient for me to just use a global of sorts the way it's already set, even if there was a basic way I could just use some sort of a statement, like, even when using a with statement in some form. It would be cool if the following simply executed the code within the statement before the create event is executed.

Code:
before with(instance_create(x,y,obj_something)){
    //code to execute before executing Create event of the newly created instance...

    //After this section, Create event of the created instance is run...
}
Or, in my case, even better if I could do this:
Code:
before with(instance = instance_create(x,y,obj_something)){
    //code to execute before executing Create event of the newly created instance...

    //After this section, Create event of the created instance is run...
}

return instance;
While this question is already solved, and I personally normally use @YellowAfterlife's script, a version I've been using more and more often is user events. While this doesn't work in every instance, in works in most and sometimes I think is a little easier to understand as the probably with the variable script is that there's no good way to know what the extra arguments are for - you just have to remember them.

Essentially, the create script of an object contains dummy values and the user event 0 contains the 'traditional' game maker create event then you create an object you do this:

Code:
///example used
var new_object = instance_create....
with (new_object) {
    //set any variables you want here
    //or run other code
    event_user(0);
}
This is a pretty flexible method and also allows you to set up different 'create' events, but it doesn't work in every case.

Edit: You can also do the above with a script rather than a user event, but this keeps an object's code a little more in one place which I like. But there are some cases where a script might be a lot better.
 

Karlstens

Member
While this question is already solved, and I personally normally use @YellowAfterlife's script, a version I've been using more and more often is user events. While this doesn't work in every instance, in works in most and sometimes I think is a little easier to understand as the probably with the variable script is that there's no good way to know what the extra arguments are for - you just have to remember them.

Essentially, the create script of an object contains dummy values and the user event 0 contains the 'traditional' game maker create event then you create an object you do this:

Code:
///example used
var new_object = instance_create....
with (new_object) {
    //set any variables you want here
    //or run other code
    event_user(0);
}
This is a pretty flexible method and also allows you to set up different 'create' events, but it doesn't work in every case.

Edit: You can also do the above with a script rather than a user event, but this keeps an object's code a little more in one place which I like. But there are some cases where a script might be a lot better.
Heya @samspade , I’ve recently hit this workflow hurdle more and more, where instance_create is called but unable to pass create event variables to that new instance prior to that new instance create event executing - this would make a great tutorial as I have found this topic again and again on the forums. I’m still undecided on which workaround to employ. This (User_Event) sounds interesting!
 

FrostyCat

Redemption Seeker
Heya @samspade , I’ve recently hit this workflow hurdle more and more, where instance_create is called but unable to pass create event variables to that new instance prior to that new instance create event executing - this would make a great tutorial as I have found this topic again and again on the forums. I’m still undecided on which workaround to employ. This (User_Event) sounds interesting!
The 2.3.8 beta has added the ability to synthetically perform the Pre-Create event, which allows for a new solution better than all others before it. When and if 2.3.8 stable gets released without major issues, I will release the solution as a free library, and there won't be any need for tutorials on this issue again.
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
The 2.3.8 beta has added the ability to synthetically perform the Pre-Create event, which allows for a new solution better than all others before it. When and if 2.3.8 stable gets released without major issues, I will release the solution as a free library, and there won't be any need for tutorials on this issue again.
I regret to inform that you could always synthetically run Pre-Create using event_perform(14,0) - I used this in GMRoomPack
 

Karlstens

Member
The 2.3.8 beta has added the ability to synthetically perform the Pre-Create event, which allows for a new solution better than all others before it. When and if 2.3.8 stable gets released without major issues, I will release the solution as a free library, and there won't be any need for tutorials on this issue again.
Hey, that sounds exciting! I'll be keen to try as soon as I'm able.

I regret to inform that you could always synthetically run Pre-Create using event_perform(14,0) - I used this in GMRoomPack
Would you happen to have more info on this technique event_perform(14,0) ? I had a look through the manual but couldn't find any numeral identifiers, so not sure what 14 and 0 refer to?

I've spent this evening attempting to use event_user(0) but it always results in my creation event executing twice and then causing a crash. Objects at the start of my game run as expected when referring to event_user(0) via their create event, but then again, when I try to create_instance it calls the original create event, which then calls event_user(0), and my object then gets confused with itself as it runs creation code twice, once incorrectly and the second time correctly... >_<

EDIT: Oh wow, reading through the Beta thread after searching for ev_pre_create , I'm hopeful that this will be what I'm after! @FrostyCat , your JSON-esk method looks perfect too. Very keen to try it.

I can't find any actual examples of how to use ev_pre_create, so would be keen for an example if anyone has one.

EDIT 2: Woop, figured out what I think may be an alternative workflow? It's probably done by others somewhere, but not that I found during my reading - but in my quick testing it seems to work. In summary, I need two methods to create an object. 1) when the room starts and 2) when an object collides with another object. Both creation methods are the same with exception to a couple of simple variables. So looking through the events whilst researching ev_pre_create, I found an event called "Room Start" which I can use to host my creation code for objects that start life in the room. And for objects created during the game, the User Events work well to run that particular code.

I think this method might do me whilst we wait (pray?) for YoYo to add some kind of Object Creation argument injection into GMS2. Again, the way FrostyCat had an example (and apologies if I've misquoted) ;

GML:
new_obj = instance_create_layer(_x,_y, "Instances",obj,
{
   animal = "cat",
   age = 7,
   name = "Mr Kitty Cat"
}
);
That would be the ultimate solution.

EDIT 3: Just confirming, that having creation code moved into a Room Start event, and also a User Event, this seems to work well. Below is one "obj_Animal" object with a white sprite. The sprite colour is adjusted by image_blend and the _animal variable set in each relevant event.

Variable init; _animal = None
Create Event; _animal = "Mouse"
User Event; _animal = "Dog"
Room Start Event; animal = "Cat"



So a catch for using this method - anything that's defined in the Create Event will be executed, so all animals start life out as a "Mouse" in this example - which could lead to code crashing issues. So no animal should be defined in Create Event.
 
Last edited:

goto100

Member
HI,

the user_event code is a very good solution to solve that kind of issue, but I use event_perform instead :

///example used
var new_object = instance_create....
with (new_object) {
//set any variables you want here
//or run other code
event_perform(ev_create, 0);
}

=> you "re"create the instance with the good values

It works fine
 
HI,

the user_event code is a very good solution to solve that kind of issue, but I use event_perform instead :

///example used
var new_object = instance_create....
with (new_object) {
//set any variables you want here
//or run other code
event_perform(ev_create, 0);
}

=> you "re"create the instance with the good values

It works fine
A) You necroed a year+ old thread for this 🙃
B) You have been able to just inject variables in the instance_create_*() function for a long time now:
GML:
instance_create_layer(x, y, layer, object, { variableA : 10, variableB : "some string", variableC : c_black });
In that example, when the instance runs its Create Event, it already has variableA, variableB and variableC initialised to the values provided in the struct (you can even just inject already created structs and the instance will inherit all the variables and corresponding values from the struct).
 

FrostyCat

Redemption Seeker
HI,

the user_event code is a very good solution to solve that kind of issue, but I use event_perform instead :

///example used
var new_object = instance_create....
with (new_object) {
//set any variables you want here
//or run other code
event_perform(ev_create, 0);
}

=> you "re"create the instance with the good values

It works fine
No, it is not good, and it doesn't work fine. It is obsolete and wrong.

Obsolete, because the options struct has been supported in instance_create_layer and instance_create_depth since 2022.5, 4 months after post #16 and over 3 years since the beginning of the thread.

Wrong, because if there are side effects in the Create event (e.g. creating visual effects, playing sounds, setting up subsidiary object instances, etc.), your "solution" would run those twice as well.

Watch out for the timestamp on threads and tutorials. Don't post replies on old stuff. Spend some time reading Release Notes and learning the latest techniques.
 
Top