Legacy GM Buttons & Doors Problem

B

Braeden Hammill

Guest
I'm making a game where there are doors that open when a specific button is being pressed and close when the button is not being touched.

I have made it so if the button is pressed it will open every door object, and my problem is I can't figure out how to give a specific button a relationship with a specific door, I've tried it once where in the step event it checks if the door and button both have a variable in common where I give them both a variable in the creation code and if I want button "A" to work with door "A" and button "B" to door "B" then the "A" buttons and "A" doors would have their variable equal "1" and the "B"'s would both equal "2". ( It didn't work )

Pls help (I have only been coding for a few months so I am not an expert)

Door Code: (without the variables that it and the button will have in common. All it says is "if button pressed, move door up, if not, move door down. pls tell me how to make a certain button activate a certain door.)

obj_door_move

_mspd = 1
_vspd = 0

if obj_button._state = obj_button._pressed
{
if y != ystart - 112
{
_vspd = _mspd
y -= _vspd
}
}
else
{
if y != ystart
{
_vspd = _mspd
y += _vspd
}
}


obj_button

_state = 0;
_pressed = 1 // if button is being touched/pressed
_notpressed = 2 //if the button was previously pressed but is now not being touched/pressed

if place_meeting(x,y,obj_player) || place_meeting(x,y,obj_box)
{
_state = _pressed
sprite_index = spr_button_press
}
else
{
_state = _notpressed
sprite_index = spr_button
}
 

TheouAegis

Member
You'll need an instance creation code for the button. Store the id of the door in a variable in the button. Then use that varaible to target the specific door.
 
B

Braeden Hammill

Guest
how do you store an instances id in a variable?
and how would I check that in the doors step event?
 

TheouAegis

Member
It wouldn't be in the door's step event. You'd have the button keep track of its state cuz everything depends on the button.

You could have the door handle everything, though. In that case, you'd get the id of the button and save it in the door. Just reversing the logic.

To get the id of the instances you placed in the room yourself, just right-click on the instance in the room and select Copy Instance Name.
 

Hyomoto

Member
A picture is worth a thousand words, so let's look at one!

Here we have two objects, one door and one switch. We've given both of them a switchValue variable. Now if you don't have GM2 you can do the same thing by putting the variable in the create event, but I'll cover that in a moment. Basically when we activate the user_event, in this case I assume by standing on the switch we run a with ( obj_door ) {} statement. This will check all the doors to see if their switchValue matches the switch we just activated. If they do, then we open them. The value of doing this is that you can have any number of doors attached to any switch, you just have to pair their switchValues. Oh, and how do we pair the doors and switches? In the room editor we can do this:

Now, to do this in GMS1.4 you do have to go about it slightly differently. You would add this variable to the 'creation code' instead. I had to demonstrate with GM2 because that's what I have and used, but it is possible to do this with GMS. Hopefully this helps, but feel free to ask if you still don't understand.
 

Hyomoto

Member
@TheouAegis If speed were a particular consideration you could do it at room start, but then we start adding complexity to shave off a very minimal speed impact. First, in order to have more doors we'd need to do something like:
Code:
// create
listOfDoors = ds_list_create();
switchValue = 10;

// room start
var _switchValue = switchValue;
var _doors = listOfDoors;
with ( obj_door ) { if switchValue == _switchValue { ds_list_add( _doors, id ) } }

// clean up
ds_list_destroy( listOfDoors );
I'll concede it's possible that if your room has dozens of doors and switches, which is plausible, this might be a better solution. But considering the open code would only be ran when the switch was depressed, or released, it's unlikely the performance hit would be significant enough to require a more elaborate solution. Though that is the joy of coding, making the thing do the stuff just how you like ;)
 

TheouAegis

Member
I was talking about just copying the ID of the button, pasting it in the Door's instance creation code, and then doing something like

if myButton.sprite_index == spr_button_press {/* door is open */}
else {/* door is closed */}


Also, if I get the jist of what you were suggesting with your other code, this would probably do the same thing and just as easily as long as you created buttons and doors in a 1-for-1 style. No Instance creation code needed, no data structures need, just a simple 1-to-1 id pairing system.

Code:
myID = instance_number(object_index);

//in step event or whatever
with obj_Button
if myID == other.myID
{
    if sprite_index == spr_button_pressed
    {/* door is open */}
    else
    {/* door is closed */}
    break;
}
 
Last edited:

Hyomoto

Member
@TheouAegis - I'd be glad to explain my method here, but it's a little more a question of how you choose to arrange your code. Your method can work, that's the fun of code. But the reason I chose the way I did is to decouple the door logic from the switch logic. This allows me greater flexibility in how I use my switches, as well as how I make my door. Consider the following example:
Code:
// create
switchValue  = 10;
switchType   = obj_door;

// user_event0 - switch pressed
var _switchValue = switchValue;

with ( switchType ) { if _switchValue == switchValue { event_user( 0 ) } }

// user_event1 - switch released
var _switchValue = switchValue;

with ( switchType ) { if _switchValue == switchValue { event_user( 1 ) } }
This switch supposes nothing about the object it will activate. Because of this, it could be used to activate a door, another switch, a trap, an enemy, etc... the only requirement being that they share a switchValue to compare. I can have many switches that do not conflict with one another, and any number of objects could be wired up to any switch however I want without making a bunch of new objects. Most importantly, however, the switch does not contain any code for the door. The switch merely tells switchType, "Hey, I activated you." Whether any object of that type exists, or whether or not that object cares, is up to the object. The switch is merely letting it know it has been pressed. This is a basic example but consider the two following doors:
Code:
// obj_door

isOpen = false;

// user_event0
isOpen = true;


// obj_door_trap -> inherits obj_door

// user_event1
isOpen = false;
The first door will open, and stay open, once it has been activated. The second door will close when the player steps off the switch. This is just simple inheritance, but coupled with our messaging above, both doors will receive the message, "Hey, the switch just deactivated." But only one of the doors responds to it. Now you might want to ask, 'Where is your step event for activating the switch?' Just as the switch calls an event on the door, something else would call an event on the switch. Whether that be a box, the player, an enemy, another switch: it won't matter. The switch only cares that it's been activated, it doesn't care what did it. There's also a big optimization in that the switch isn't running code each step searching for a player that might not be anywhere near it.

In the end, the most basic benefit should be clear. This is dead simple, easy-to-understand, easy-to-write, and easy-to-extend code that is easily maintainable. And unlike the method you suggested, there is no spaghetti: you could delete the door, or the switch, and all other objects would continue to function. If I may preach a little bit, code like this is an absolute joy to write and work with.
 
Last edited:
B

Braeden Hammill

Guest
A picture is worth a thousand words, so let's look at one!

Here we have two objects, one door and one switch. We've given both of them a switchValue variable. Now if you don't have GM2 you can do the same thing by putting the variable in the create event, but I'll cover that in a moment. Basically when we activate the user_event, in this case I assume by standing on the switch we run a with ( obj_door ) {} statement. This will check all the doors to see if their switchValue matches the switch we just activated. If they do, then we open them. The value of doing this is that you can have any number of doors attached to any switch, you just have to pair their switchValues. Oh, and how do we pair the doors and switches? In the room editor we can do this:

Now, to do this in GMS1.4 you do have to go about it slightly differently. You would add this variable to the 'creation code' instead. I had to demonstrate with GM2 because that's what I have and used, but it is possible to do this with GMS. Hopefully this helps, but feel free to ask if you still don't understand.

Since I am using GMS 1.4 I am not sure what "variable definitions" are, and in the "switch" code at the top, it says "when the switch is pressed". So am I making the code for checking if the switch is pressed in another step event/script or do I just put it at the top of the statement? (sry to bother I'm dum )
 

Hyomoto

Member
@Braeden Hammill - Well I have to apologize, I thought GMS still had "creation code" for objects as part of it's room editor but it seems that is also a GM2 feature. So my idea isn't quite as flexible in GM1.4. We can still make use of it with a little bit more work but the problem is, without having some ability to 'customize' each instance from the room editor you would need to specify every switch object/door pair and that would get complicated fast. Basically the whole reason I suggested this idea was for flexibility and it turns out GM1.4 can't really make use of it. However, with a little conversion we can make it work at the cost of some major functionality. First, we would declare our variables in the create event:
Code:
/// create_event
switchValue = 10;
Now, the part of this idea that is still beneficial is that we would put the 'switch activate' code into a 'user event'. The user events are code that is part of an object that can only be called by using event_perform. The benefit of that is we can attach personalized code to an object that will only be called when we want it to. In this case, it also allows us to reuse some of our code between different objects. For example, if we want the switch to be activated by pushing a crate onto it, or the player walks on to it. Instead of putting the activation code into the player object, for example, we keep that in the switch object and now we can share it with anyone.

However, calling that actual event would go, in this case, on the player object, probably in a step event that checks if the player has collided with the switch.
 
B

Braeden Hammill

Guest
@Braeden Hammill - Well I have to apologize, I thought GMS still had "creation code" for objects as part of it's room editor but it seems that is also a GM2 feature. So my idea isn't quite as flexible in GM1.4. We can still make use of it with a little bit more work but the problem is, without having some ability to 'customize' each instance from the room editor you would need to specify every switch object/door pair and that would get complicated fast. Basically the whole reason I suggested this idea was for flexibility and it turns out GM1.4 can't really make use of it. However, with a little conversion we can make it work at the cost of some major functionality. First, we would declare our variables in the create event:
Code:
/// create_event
switchValue = 10;
Now, the part of this idea that is still beneficial is that we would put the 'switch activate' code into a 'user event'. The user events are code that is part of an object that can only be called by using event_perform. The benefit of that is we can attach personalized code to an object that will only be called when we want it to. In this case, it also allows us to reuse some of our code between different objects. For example, if we want the switch to be activated by pushing a crate onto it, or the player walks on to it. Instead of putting the activation code into the player object, for example, we keep that in the switch object and now we can share it with anyone.

However, calling that actual event would go, in this case, on the player object, probably in a step event that checks if the player has collided with the switch.

Sorry if I was confusing, GMS 1.4 DOES have creation code and instead I was not sure what "variable definitions" are. (are they the same thing?) I was also asking about the code in the "switch" event because at the top it says, this is what happens if the button is being touched, so where do I check if the button is touched? Or do i just do it at the top of the statement?

Sorry if I was unclear.
 

Hyomoto

Member
Well, in GM2 they recently added the ability to define variables as part of objects before the create event. The idea was that sometimes you want to make a determination about the state of the object during the create event. The semantics are different but a variable is a variable, as long as you define it you'll be fine.

As for the switch event, consider the following example:
Code:
// player step_Event
var _id == id;

with ( obj_switch ) {
  if point_distance( x, y, _id.x, _id.y ) < 10 { event_perform( ev_other, ev_user0 ) }

}
There's a reasonably good chance your player object is already checking for collisions with objects; the idea is that you keep the behavior of the switch in the switch object, but you call that behavior from the player. As I mentioned above this has a few benefits. First off, you could delete the switch, or the player, and neither object would cease to function correctly. Second, you keep all your code nice and neatly packaged with where it is relevant. And lastly, because of the first two points, you can also then easily extend this code to other things. As I mentioned, you might decide you want a switch to also be able to activate when you put a crate on top of it. Instead of having to rewrite the same switch logic in the player and the crate, you'd simply call the same block of code. So to answer your question, the switch would have the code to execute when the player steps on it, but the call to execute that code would be part of the player object and likely during the a step event.
 
Top