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

SOLVED [SOLVED] Passing object_index to function instead of one instance / Making functions work like with (kinda)

Howdy, I assumed this would be an easy issue / have tons of similar threads on it already, but I can't seem to find any. What I'm trying to do I thought would be very simple, but it's proving to be troubling for me. Hopefully I'm just being stupid and there is an easy solution:

I want to (easily) pass an object_index into a function, instead of a single instance of that object type.

Essentially, I would like to use functions as proxies for the with() statement, where I can pass in either a single instance derived from a given object type or operate on many instances from that object type. In other words, I want to delay when the object type is evaluated by the with() statement via a function. That's still a bit confusing to word, so here's my code:

I was writing this a lot:

GML:
with(obj_my_type)
{
    drawingActive = true;
    drawingActive = true;
    image_blend = c_white;
}
But with different object types (instead of obj_my_type), plus setting those two variables to false instead of true half the time. Seems like the perfect place to write a function, right?

GML:
/// @function show_hide_object(_obj, _show)
/// @param {id}        _obj                The object to show or hide with default blend
/// @param {bool}    _show                Whether to show the object or hide the object
function show_hide_object(_obj, _show)
{
    with(_obj)
    {
        drawingActive    = _show;
        logicActive        = _show;
        image_blend = c_white;
    }
}
Seems good. This cuts down my code significantly, makes almost the entire project more readable and way shorter in length. It's crazy how much that added up.

GML:
// Hide and disable GUI buttons
show_hide_object(obj_gui_button_clear, false);
show_hide_object(obj_gui_button_deal, false);
However, now it doesn't work unless there's a single instance of the given object type, only operating on the first _obj it finds. Of course, makes sense, I expected that. And 95% of the time there is guaranteed to only be one instance of that object type. But sometimes I need to hide or show an entire object type at once, but I figured that would simple as the following:

GML:
// Hide and disable GUI buttons
show_hide_object(obj_gui_button_clear, false);
show_hide_object(obj_gui_button_deal, false);
show_hide_object(obj_chip.object_index, false); // Hide chip dock
Adding a .object_index into the argument when called I thought would do the trick, passing the object_index object type itself instead of the instance id of the first instance of that object type found, so then in the show_hide_object() function the with() statement would run the code on all instances of that object type.

This was false. obj_my_type.object_index seems to evaluate into the exact same thing as obj_my_type, namely the instance id of the first instance of that object type found. I guess that makes sense... but that's rather disappointing and annoying. I've been looking around for some function or something to alleviate this problem, letting me pass an object_index itself into my above show_hide_object() function even if the calling line itself is more annoying, but I've come up empty.

I'd ideally like to be able to call show_hide_object() with a given object_index even if there are 1 or 200 instances of that object type.
However, I'd be happy enough if I had to make a near duplicate version of show_hide_object() that's just for when there are many instances of a given object type instead of guaranteed just one.

Do you have any solutions to this? Am I just being stupid?

I appreciate your time and help, thanks le million!
 

TsukaYuriko

☄️
Forum Staff
Moderator
However, now it doesn't work unless there's a single instance of the given object type, only operating on the first _obj it finds. Of course, makes sense, I expected that.
No. Does not make sense, at all. with(object) should apply to all instances of that object without fail.

Adding a .object_index into the argument when called I thought would do the trick, passing the object_index object type itself instead of the instance id of the first instance of that object type found, so then in the show_hide_object() function the with() statement would run the code on all instances of that object type.

This was false. obj_my_type.object_index seems to evaluate into the exact same thing as obj_my_type, namely the instance id of the first instance of that object type found.
It evaluates to the same thing because obj_my_type is an object index and the object index of its first instance is, naturally, also an object index. So, yes, they evaluate to the same, except the latter crashes if there is no instance of the object.

It's a bit ironic, really. You try to avoid getting the first instance of the object involved, but it's only when you try to read from its object_index that you're involving it in the first place. Simply putting the object there will not even touch anything related to its instances.

To clarify: There's no magic related to object resource names. They're constants that hold object IDs. They will not return the ID of the first instance of that object under any circumstances. They're not context-aware. It's where these IDs are used that the magic happens. So, with statements, when provided an object index, will apply the operation to all instances of that object, reading variables from an object index will resolve to the first instance of that object, and so on.


My main point is that what you're doing should work, provided that you do it correctly and there is no external interference. Try to recreate this in an isolated project to verify that it works (and I just tested that it does, so that's more like "verify that your installation isn't broken"). It seems more likely that there is something else that is interfering with this, because this works exactly the way you're doing it.
 

Vusur

Member
However, now it doesn't work unless there's a single instance of the given object type, only operating on the first _obj it finds. Of course, makes sense, I expected that
But that shouldn't happen. with(...) in combination with an object (not instance) is a 'hidden loop'. It iterates through all instances, that are created with this object.
So this:

GML:
function show_hide_object(_obj, _show)
{
    with(_obj)
    {
        drawingActive    = _show;
        logicActive        = _show;
        image_blend = c_white;
    }
}
in combination with this:

GML:
show_hide_object(obj_gui_button_clear, false);
should hide ALL instances of obj_gui_button_clear. If there is 0 or 100 doesn't matter. With 0 instances, it does nothing, with 100 instances, all 100 are set to false.

with(...) is also increadible smart. Assuming you have a obj_button_parent object definition, a obj_button_child1 and a obj_button_child2 object definition. Now both children have the same parent. show_hide_object(obj_button_parent, false); would hide all parent buttons and also all child1 and child2 buttons. Neat, when you can group objects and it reduces even more code... sometimes.

So with(...) is not only a hidden loop with the given object, but it also loops through all child object/instances.

BTW: var temp = obj_chip.object_index or to make it more clear var temp = obj_chip.aVariableWithin is - again - a 'hidden loop'. It iterates through all instances of obj_chip and returns the value of aVariavleWithin of the last instance encountered. What is the last instance? Who knows. ('Who knows" is not a real answer, you can know it if you try, but I don't see a use case for this approach. Other solutions would be better)

When working with obj_something - objects - you can think of it as working with a container, drawer of whatever. As soon as you write the object name in your code, you call all instances of it.

Are you familiar with OOP programming languages? Classes and objects? Objects in GM are like classes, while instances in GM are like objects. Confusing, because both use the term 'object', but if you know the OOP concept, it's a good and naive analogy.

Edit: Stop, Vusur. You did it again! I crossed something out. I always think it takes the last instance. But it takes the first. Now I got confused.
 
Last edited:
No. Does not make sense, at all. with(object) should apply to all instances of that object without fail.


It evaluates to the same thing because obj_my_type is an object index and the object index of its first instance is, naturally, also an object index. So, yes, they evaluate to the same, except the latter crashes if there is no instance of the object.

It's a bit ironic, really. You try to avoid getting the first instance of the object involved, but it's only when you try to read from its object_index that you're involving it in the first place. Simply putting the object there will not even touch anything related to its instances.

To clarify: There's no magic related to object resource names. They're constants that hold object IDs. They will not return the ID of the first instance of that object under any circumstances. They're not context-aware. It's where these IDs are used that the magic happens. So, with statements, when provided an object index, will apply the operation to all instances of that object, reading variables from an object index will resolve to the first instance of that object, and so on.


My main point is that what you're doing should work, provided that you do it correctly and there is no external interference. Try to recreate this in an isolated project to verify that it works (and I just tested that it does, so that's more like "verify that your installation isn't broken"). It seems more likely that there is something else that is interfering with this, because this works exactly the way you're doing it.
Thank you so much for your speedy reply, TsukaYuriko!

Every time I begrudgingly post a thread I keep thinking that 'oh well they're fast, maybe I'll get something in a few hours or tomorrow morning...' and this community more than exceeds my expectations with such instantaneous and well-thought out help! The GameMaker forums and community are the best in the industry in my experience, and as much as I do love the GameMaker software itself and YoYo's licensing model, it's really this incredible community that keeps me here using GM even though everyone else in my field uses Unity and finds me weird and begs me to switch and I get a Unity rep knocking down my door every six months haha...

You are absolutely right, and thanks to you pointing me in the right direction I resolved the problem! I had to take it into a separate test project as you recommended, and with some fiddling copying over and over the more complex systems of the surrounding project, I was able to isolate the problem, which was some interference as you mentioned.

It was simultaneously uplifting and disheartening to find that my original conceit about GM functions and with() was in fact correct... but that it was actually my fault through some other outside aspect of my system. 😅

And thank you for the better explanation of object indexes! For some reason (I think it may literally be because of a dumb tutorial I watched some 6 years ago), I was under the impression that obj_my_type resolved in-line when run to become the instance ID of the first instance found, and then through some shenanigans with() ran it on all instances of that instance's object type... or something. Actually typing it out now, that sounds even dumber than I thought it was in my head. And I thought it was really dumb.

To clarify: There's no magic related to object resource names. They're constants that hold object IDs. They will not return the ID of the first instance of that object under any circumstances. They're not context-aware. It's where these IDs are used that the magic happens. So, with statements, when provided an object index, will apply the operation to all instances of that object, reading variables from an object index will resolve to the first instance of that object, and so on.
It's that dot-operator part that really got me. When you run var _v = obj_my_type.x; it resolves to the first instance found, not all of them simultaneously of course. I believe that's where my confusion really originated, from that interaction and some old tutorial (lol) giving me a false impression of how and when things resolved.

I'm overjoyed to have that confused idea corrected. The proper workings of object_indexes / when object_indexes become instance IDs has always been the #1 thing I was confused about in GM, particularly because of the dot operator and with() cases.

So now if I'm understanding right:
  • obj_my_type is-actually the object index of that object resource, like you'd expect, same as returned by _inst.object_index (where _inst is an instance of that object) and it's only resolved into a single instance ID when you use the <.> dot operator to access a variable to-read (e.g., obj_my_type.myVar) not-write.
  • The with() statement runs the code block on all instances of the given object type, regardless of the number of instances (0 to infinity), OR it runs the code block on the given instance ID (such as returned by instance_create_layer). For the sake of explanation, you could essentially consider with() to have two overloaded calls, accepting either an object index or instance ID value.
Is that correct? Is there another case where an obj_my_type becomes a single instance like with the read-dot-operator beyond functions handling it smartly?

It's a bit ironic, really. You try to avoid getting the first instance of the object involved, but it's only when you try to read from its object_index that you're involving it in the first place. Simply putting the object there will not even touch anything related to its instances.
I thought the same thing as typing it, that this would crash if there ever wasn't an instance for some reason, and said to myself "if this works it'll be really dumb" as a necessary work-around. Now I'm glad it didn't work, as your truthful explanation of object_index is much more convenient and logical, even if it was annoying to find the real bug.

Thank you again for the Sonic Speed reply and help. You're a rock star. I really appreciate it, more than you know. I'm the sole game developer at my company, and sometimes I just really wished I had another pair of eyes to help bounce ideas off of and catch me when I'm being silly, like here. We always need another head sometimes. I'm incredibly grateful so many smart heads like yours willingly provide their assistance on-the-fly on these forums.

If there's anything I can ever do to return the favor / support you, whether that's providing my own fresh pair of eyes on your own problem, watching your YT channel, reading your blog, buying your Steam game, etc. (IDK what you do), please just let me know. Thanks!
 
But that shouldn't happen. with(...) in combination with an object (not instance) is a 'hidden loop'. It iterates through all instances, that are created with this object.
So this:

GML:
function show_hide_object(_obj, _show)
{
    with(_obj)
    {
        drawingActive    = _show;
        logicActive        = _show;
        image_blend = c_white;
    }
}
in combination with this:

GML:
show_hide_object(obj_gui_button_clear, false);
should hide ALL instances of obj_gui_button_clear. If there is 0 or 100 doesn't matter. With 0 instances, it does nothing, with 100 instances, all 100 are set to false.

with(...) is also increadible smart. Assuming you have a obj_button_parent object definition, a obj_button_child1 and a obj_button_child2 object definition. Now both children have the same parent. show_hide_object(obj_button_parent, false); would hide all parent buttons and also all child1 and child2 buttons. Neat, when you can group objects and it reduces even more code... sometimes.

So with(...) is not only a hidden loop with the given object, but it also loops through all child object/instances.

BTW: var temp = obj_chip.object_index or to make it more clear var temp = obj_chip.aVariableWithin is - again - a 'hidden loop'. It iterates through all instances of obj_chip and returns the value of aVariavleWithin of the last instance encountered. What is the last instance? Who knows. ('Who knows" is not a real answer, you can know it if you try, but I don't see a use case for this approach. Other solutions would be better)

When working with obj_something - objects - you can think of it as working with a container, drawer of whatever. As soon as you write the object name in your code, you call all instances of it.

Are you familiar with OOP programming languages? Classes and objects? Objects in GM are like classes, while instances in GM are like objects. Confusing, because both use the term 'object', but if you know the OOP concept, it's a good and naive analogy.

Edit: Stop, Vusur. You did it again! I crossed something out. I always think it takes the last instance. But it takes the first. Now I got confused.
Thank you so much for the fast reply, @Vusur!

You're absolutely right. Unfortunately (/ fortunately?) I didn't see this comment until after I had resolved the problem by hunting down the real bug after @TsukaYuriko pointed me in the right direction, however I do really appreciate your time and clarification!

with(...) is also increadible smart. Assuming you have a obj_button_parent object definition, a obj_button_child1 and a obj_button_child2 object definition. Now both children have the same parent. show_hide_object(obj_button_parent, false); would hide all parent buttons and also all child1 and child2 buttons. Neat, when you can group objects and it reduces even more code... sometimes.
God I know with() is so f*&%ing cool! I said in my previous reply that the GameMaker Community / Forums is the main thing that keeps me to GM instead of Unity, Unreal, or Godot... but honestly the Forums do kinda hold second-fiddle to me compared to with(). It's so incredibly convenient... Every single one of my projects is just wall-to-wall with() statements (with attempts to optimize out unnecessary calls for the sake of performance). Doing the same in any competitor engine was always a pain. The with() statement has always been by far my favorite aspect of GameMaker.

For an interview I did espousing the virtues of GameMaker a couple years ago, I even said that with() statement was my favorite thing about GM lol... though that part of the answer was (reasonably) cut for time. I'm incapable of giving short replies to questions, especially open-ended questions about my likes and preferences haha...

I didn't even mention the inheritance aspect as I just always assume it will work, as GM and with() handles inheritance so perfectly, I never even have to think about it, but yeah in my actual project almost every single object I'm using show_hide_object() is a parent or a child resolving complex relationships and triggers in such a clean, neat, simple way. It's great.

As soon as you write the object name in your code, you call all instances of it.
Yeah, my confusion was really with my understanding of when / where in-code the object name became the instance(s). I think I understand it now thanks to @TsukaYuriko, though if my reiterated explanation at the bottom of my reply to them is incorrect in any way, please shout it out.

Are you familiar with OOP programming languages? Classes and objects? Objects in GM are like classes, while instances in GM are like objects. Confusing, because both use the term 'object', but if you know the OOP concept, it's a good and naive analogy.
Yeah haha... I often try to use the same analogy when I'm attempting to indoctrinate my other CS / gamedev friends into GameMaker, and I wish we had separate, better terms. It's always a bit confusing. When I'm speaking to a GM-specific audience where I can't assume OOP knowledge like in my original post, I try to use the terms "instance" and "object type" to differentiate and get at my meaning, though IDK how effective that is.
I come from a low-level C/C++/Assembly background, and my earliest days in gamedev programming—outside of Portal modding and producer-like non-programmer roles in game teams—were in a lot of proprietary Unity-like engines. I love GM and have been using it professionally for years now, but some of that transition from other engines and languages still rubs against me sometimes, where some quirks or term in GM catches me off-guard or confuses me. Obviously every time I post here on the Forums is most definitely going to be one of those cases, as I'm asking about something I don't understand haha...

Anyway, thank you again for the reply and clarification @Vusur!

I'm going to continue to say this in every one of my threads and like nobody takes me up on the offer, but I'm serious:
If there's ever any way I can return the favor, whether that's buying your Steam game or watching your YouTube videos about anything, however I could best support you, please let me know!

You GM Forums regulars are the backbone of this community and what really makes GM so special. I really appreciate your time. Thanks!
 

TsukaYuriko

☄️
Forum Staff
Moderator
So now if I'm understanding right:
  • obj_my_type is-actually the object index of that object resource, like you'd expect, same as returned by _inst.object_index (where _inst is an instance of that object) and it's only resolved into a single instance ID when you use the <.> dot operator to access a variable to-read (e.g., obj_my_type.myVar) not-write.
  • The with() statement runs the code block on all instances of the given object type, regardless of the number of instances (0 to infinity), OR it runs the code block on the given instance ID (such as returned by instance_create_layer). For the sake of explanation, you could essentially consider with() to have two overloaded calls, accepting either an object index or instance ID value.
Is that correct? Is there another case where an obj_my_type becomes a single instance like with the read-dot-operator beyond functions handling it smartly?
Sounds correct to me. Since you brought up that terminology, you could think of the "reading variable from object" case as another scenario with two overloaded calls, one where you pass an instance ID to read a variable from, and another where you pass an object ID (and that's where it resolves from the object ID to the ID of its first instance).

Reading variables is the only case that comes to mind where object IDs are resolved into a single instance. There's another case where object IDs are resolved to a variable number of instances, though, and that's writing to an object's variables. This will resolve to all instances of the object in the room, unless there are none, in which case you'll get donked with a crash instead.

This is what makes it possible to set variables of an instance by referring to it via its object ID when there's only one instance of it in the room (e.g. obj_player.hp-- for making the player take damage), as well as the reason why trying to apply the same logic for enemies (obj_enemy.hp--) will make all enemies take damage instead of the one you just hit, no matter how strongly newbies want to believe that object IDs in a Collision event (or when used in conjunction with collision functions) will automatically resolve to the thing they just hit. We get "all of my enemies are dying instead of just one" a lot around here. :D


Thank you again for the Sonic Speed reply and help. You're a rock star. I really appreciate it, more than you know. I'm the sole game developer at my company, and sometimes I just really wished I had another pair of eyes to help bounce ideas off of and catch me when I'm being silly, like here. We always need another head sometimes. I'm incredibly grateful so many smart heads like yours willingly provide their assistance on-the-fly on these forums.
The appreciation is mutual! It's always a pleasure to help people who clearly put some thought into trying to resolve and understand their issues. :)
 
Top