GML Visual How do I send info to the nearest instance?

M

MGStudios7

Guest
New to GameMaker, and I'm working on a unique type of tower defense game. The idea is that you control a character and have to mine resources and find/create crystals that provide power to the towers allowing them to shoot when the crystal is placed near the tower. Some crystals are better than others and provide higher damage or shooting speed to the towers. So basically I need to make it so the crystal sends out a message to all towers within range and automatically adjusts the towers damage and attack speed n all that, but I can't figure out how to do that. In other words I want the crystals to "change these specific variables in all towers within range, and if they go back out of range change it back to what it was before".

Also I'm bad at coding so I've been using the DnD method. I've attached my extremely simple game below, and as you can see (if you open it) the green diamond represents the crystal, and I was able to get the tower to shoot when the crystal is nearby. But that's all done within the towers programming. I need to figure out how to do that within the crystals programming and send that information to the tower.

 

jo-thijs

Member
New to GameMaker, and I'm working on a unique type of tower defense game. The idea is that you control a character and have to mine resources and find/create crystals that provide power to the towers allowing them to shoot when the crystal is placed near the tower. Some crystals are better than others and provide higher damage or shooting speed to the towers. So basically I need to make it so the crystal sends out a message to all towers within range and automatically adjusts the towers damage and attack speed n all that, but I can't figure out how to do that. In other words I want the crystals to "change these specific variables in all towers within range, and if they go back out of range change it back to what it was before".

Also I'm bad at coding so I've been using the DnD method. I've attached my extremely simple game below, and as you can see (if you open it) the green diamond represents the crystal, and I was able to get the tower to shoot when the crystal is nearby. But that's all done within the towers programming. I need to figure out how to do that within the crystals programming and send that information to the tower.

Hi and welcome to the GMC!

You can probably do something similar to the example in the docs for the "If Collision Shape" action.
If neither the towers, nor the crystals ever move, grow or shrink between being created and being destroyed,
you can use that action in the create event and the destroy event of the crystals.
In the create event, you check for all collisions with a tower within a circle.
You then loop through every collision and increase the stat variables of the respective tower.
In the destroy event you do the same, but decrease the stat variables by the same amount.

You can use GameMaker's parent system to reduce duplicate code, so you don't have to repeat the collision code for every individual tower object.

If you only want to find the nearest (crystal) instance, you can assign the value:
GML:
instance_nearest(x, y, your_object_name_here)
to some variable (in the tower object), check if that variable equals the value "noone" (to check if there are any active instances of object crystal in the room at all)
and if it isn't equal to "noone", then the variable will contain the instance ID of the nearest (crystal) instance.

I hope this helps. If you have any questions, feel free to ask them!

PS: I don't have GameMaker:Studio 2 myself, so I can't look at your project in it and I can't double check my suggestions.
 
M

MGStudios7

Guest
Hi and welcome to the GMC!

You can probably do something similar to the example in the docs for the "If Collision Shape" action.
If neither the towers, nor the crystals ever move, grow or shrink between being created and being destroyed,
you can use that action in the create event and the destroy event of the crystals.
In the create event, you check for all collisions with a tower within a circle.
You then loop through every collision and increase the stat variables of the respective tower.
In the destroy event you do the same, but decrease the stat variables by the same amount.

You can use GameMaker's parent system to reduce duplicate code, so you don't have to repeat the collision code for every individual tower object.

If you only want to find the nearest (crystal) instance, you can assign the value:
GML:
instance_nearest(x, y, your_object_name_here)
to some variable (in the tower object), check if that variable equals the value "noone" (to check if there are any active instances of object crystal in the room at all)
and if it isn't equal to "noone", then the variable will contain the instance ID of the nearest (crystal) instance.

I hope this helps. If you have any questions, feel free to ask them!

PS: I don't have GameMaker:Studio 2 myself, so I can't look at your project in it and I can't double check my suggestions.
Thanks for the response! The towers never move, but the crystals do (the player character will be able to pick them up and move them). I tried using the If Collision Shape action and that part works, but after that I'm trying to assign a variable to the tower that triggered the If Collision Shape and I'm having trouble with that. I thought I'd be able to do an Assign Variable to "Other" but that doesn't seem to work. I recently read up on how the "Other" option works and to my understanding when Other is used during a collision event, it applies itself to the object that triggered the collision. Maybe I'm misunderstanding how "Other" works? Or am I just not executing it correctly?

Here's some images of my program. First two pics are the tower, and the last one's the gem (or crystal. Haven't decided on a name yet lol). Idk if this is the best way to do this, but as you can see I assigned a variable to the tower called gem_range which will act as a true or false variable (1 meaning true, and 0 false). I want the gem to change that variable in the tower to 1 when it comes in range (and back to 0 when it goes out of range but I'll figure that out later), so I have an Assign Variable action in the gem set to Other which doesn't seem to be working. From looking at this can you see anything I'm doing wrong?

Capture.PNG
Capture 2.PNG
Capture 3.PNG
 

jo-thijs

Member
Thanks for the response! The towers never move, but the crystals do (the player character will be able to pick them up and move them).
When the player picks up a gem/crystal, does the instance get destroyed or does it teleport to the player?

I tried using the If Collision Shape action and that part works, but after that I'm trying to assign a variable to the tower that triggered the If Collision Shape and I'm having trouble with that. I thought I'd be able to do an Assign Variable to "Other" but that doesn't seem to work. I recently read up on how the "Other" option works and to my understanding when Other is used during a collision event, it applies itself to the object that triggered the collision. Maybe I'm misunderstanding how "Other" works? Or am I just not executing it correctly?
That's kind of how the "other" keyword works, but there's more to it.
First of all, you are right in that the collision event makes the other keyword refer to the instance that is colliding with the executing instance and triggered the event as a result.
However, you are not using the collision event, you're using the "If Collision Shape" action, which does not alter what "other" refers to.

Now, the keyword other actually has a different meaning.
In GameMaker, you have a with-construction, with a corresponding "Apply To..." action.
With this construction/action, you can tell some instance A to make some instance B perform some specific code.
In the body of this construction/action, you won't be using the instance scope of instance A anymore, but the instance scope of instance B.
This means that when you refer to variables for example, you will be referring to the variables of instance B and not those of instance A, as you would outside the body.
You will often still need to refer to variables of instance A from inside a with-construction / "Apply To..." action however and this is where the "other" keyword comes into play.
Within the body of a with-construction / "Apply To..." action, the "other" keyword refers to the instance that called the construction/action (instance A).

Outside of a with-construction / "Apply To..." action, the "other" keyword will refer to:
1) the other instance involved in a collision when inside a collision event
2) the executing instance (self) otherwise

The way I like to think of this however, is that GameMaker calls collision events of objectA with objectB as follows:
GML:
// This gets executed at the end of the step event in objectA
with objectB { // We now make instances of objectB execute some code
    if place_meeting(x, y, other) { // If the current objectB instance overlaps with "other", which refers to the objectA instance
        with other { // Then make the objectA instance execute some code
            event_perform(ev_collision, objectB); // Perform the collision event where "other" now refers to the overlapping objectB instance
        }
    }
}
This view unifies the interpretation of the "other" keyword in with-constructions / "Apply To..." actions with the interpretation of the other keyword in collision events.

Anyway, that's some background on the topic of the "other" keyword, but it isn't super relevant to your current issue.

Here's some images of my program. First two pics are the tower, and the last one's the gem (or crystal. Haven't decided on a name yet lol). Idk if this is the best way to do this, but as you can see I assigned a variable to the tower called gem_range which will act as a true or false variable (1 meaning true, and 0 false). I want the gem to change that variable in the tower to 1 when it comes in range (and back to 0 when it goes out of range but I'll figure that out later), so I have an Assign Variable action in the gem set to Other which doesn't seem to be working. From looking at this can you see anything I'm doing wrong?

Capture.PNG

Capture 2.PNG

Capture 3.PNG
Knowing now that the "other" keyword won't work, you'll have to follow the example in the docs about the "If Collision Shape" action more closely.
They have "Return List" checked and have "inst_list" as "Target".
As the docs explain, this makes the action store all the colliding instances (towers) inside a ds_list inside the variable inst_list.
In the example, they then loop through every instance (tower) in the list.
For each tower, they then use an "Apply To..." action to assign a value to a variable of the (tower) instance currently being iterated over.
At the end, they also clean up the ds_list, which you should do too in order to avoid memory leaks.
 
M

MGStudios7

Guest
So after studying and reading your response many times, I was able to get some things working, but still running into other problems. It's probably best if I just keep making my way through more tutorial series's and then come back to this later. Thanks a lot for the help!
 
Top