GML [SOLVED] Multi-Switch Logic is Broken

Papa Doge

Member
I'm working on a test room for my game that includes objects that have active and inactive states that are toggled when the player throws a Projectile that hits a Switch in the same room.

So far, I'm playing with the following objects...

- Switches that toggle the states of doors and platforms
- Platforms that move left/right based on a set speed if they are active
- Doors that open and close depending on whether they are active
- Projectiles that the player throws to change the state of a Switch

I wrote out my switch logic like this...

1) Player throws a Projectile
2) When a Projectile collides with Switch, store the Switch's ID and State as values in a Switch Array
3) In the Platform and Door's step events, check to see if the ID stored in the Switch Array matches that object's ID. If the IDs between Switch and Platform/Door match, then make the sate of the Platform/Door match that of the Switch.

Here's what the code looks like for the Switch when hit by a Projectile. You can ignore the hitDelay stuff. That's just so I'm not registering multiple hits on a single Switch...

Code:
// SWITCH LOGIC

// set your button hit delay to be one less frame than last frame or 0...
hitDelay = max(hitDelay-1,0);

// if the hit delay is 0 then register a new projectile hit...
if (hitDelay == 0) {
    // if the button is colliding with a projectile...
    if (place_meeting(x,y,obj_projectile)) {
        if (hit == true) { // if the switch is turned on...
            hit = false; // turn it off...
        } else { // otherwise the switch is off...
            hit = true; // so turn it on...
        }
        hitArray[0] = other.ID; // store the ID of the switch that's being hit, e.g. "A", "B", etc for the list
        hitArray[1] = hit; // store the state of this hit switch as a variable for the list
        show_debug_message("hitID = " + string(hitArray[0]));
        show_debug_message("switchState = " + string(hitArray[1]));
        hitDelay = hitDelayMax; // reset hit delay on the switch
    }
}
I know this part is working correctly because my debug messages come back with the proper values for Switch ID and State.

Here's the code for Platforms to detect if a connected Switch is being toggled in the room...

Code:
// SWITCH LOGIC

// if this platform has an ID that matches a switch that's flipped on...
if (obj_switch.hitArray[0] == ID) && (obj_switch.hitArray[1] = true) {
    active = true; // turn the platform on...
}

// if this platform has an ID that matches a switch that's flipped off...
if (obj_switch.hitArray[0] == ID) && (obj_switch.hitArray[1] = false) {
    active = false; // turn the platform off...
}

// if the platform is active...
if (active == true) {
    if (place_meeting(x+hsp,y+vsp,par_obj_collisions)) { // and if it runs into an obstacle...
        // reverse it's movement variables
        hsp = -hsp;
        vsp = -vsp;
    }
    // then move the platform...
    x += hsp;
    y += vsp;
}
And here's the code for the Doors which is the exact same as the Platforms...

Code:
// if this platform has an ID that matches a switch that's flipped on...
if (obj_switch.hitArray[0] == ID) && (obj_switch.hitArray[1] = true) {
    active = true; // turn the platform on...
}

// if this platform has an ID that matches a switch that's flipped off...
if (obj_switch.hitArray[0] == ID) && (obj_switch.hitArray[1] = false) {
    active = false; // turn the platform off...
}
The Door's active state is checked as part of a collision event with the Player object that looks like this...

Code:
// if the door is open...
if (active == true) {
    // and the door and player are colliding...
    with (obj_player) {
        // reposition the player in the next room...
        x = other.targetX;
        y = other.targetY;
        // then switch rooms...
        room_goto(other.connectedRoom);
    }
}
----------

Now in my testing room I have the following setup which I also included as an annotated screenshot so you can get a visual of how the room is laid out.

Screen Shot 2019-01-26 at 4.06.04 PM.png

- 2 Switches. The first has an ID of "A" and the second has an ID of "B"
- 2 Doors. The first Door has an ID of "N/A" so that it's not connected to either of the Switches. The second has an ID of "B" so that it's connected to the second Switch.
- 2 Platforms. The first Platform has an ID of "A" so it should be connected to the first Switch. The second has an ID of "B" and is connected to the second Switch.

Here's what it looks like when the Player hits a Switch with a Projectile...

Screen Shot 2019-01-26 at 4.41.34 PM.png

----------

Now that you have the context, I can describe the issue I'm seeing.

Switch "B" works perfectly. The projectile hits the Switch, my debugging messages come back and show the same as what's happening in the game, and both Platform "B" and Door "B" perform flawlessly.

The Door on the left side ignores both Switches as intended because it's ID is set to "N/A" which won't match a Switch.

Switch "A" is showing the correct values in my debugging messages but Platform "A" does not move at all. So the tried the following remixing of the ID values to see how the "broken" Platform behaves...

Testing Scenario 1 - Changing the ID of Platform "A" to "B" results in both Platforms and the right side Door toggling as I would expect. Switch "A" obviously didn't do anything because it's not connected to anything.

Testing Scenario 2 - Changing the ID of both Platforms to "A" results in neither Platform working when the "A" Switch is hit but the door still works with the "B" Switch.

Testing Scenario 3 - Changing both Platforms to ID "B" results in both platforms working when the "B" Switch is hit but the Door with ID "A" doesn't work when I hit Switch "A".

So I've concluded that no matter what the setup in the room, only the "B" Switch is working even though the Switch Array is updating correctly ever time a Switch is hit.

I'm stumped and not sure what to test next!
 

chamaeleon

Member
I'm stumped and not sure what to test next!
Are there more than one instance of obj_switch? You didn't spell out clearly what objects exist by name, and which instance is of what type, you're leaving it up to interpretation. Anyway, if your two switches are of type obj_switch, using obj_switch.hit_array[] in your code is likely not what you'd want to use, as GMS would pick one instance (probably the same one all the time, perhaps switch B) to use as the representative to get the data out of.
 

Papa Doge

Member
Are there more than one instance of obj_switch? You didn't spell out clearly what objects exist by name, and which instance is of what type, you're leaving it up to interpretation. Anyway, if your two switches are of type obj_switch, using obj_switch.hit_array[] in your code is likely not what you'd want to use, as GMS would pick one instance (probably the same one all the time, perhaps switch B) to use as the representative to get the data out of.
Yeah, you can see the object instances I'm using in the first screenshot. The two purple boxes are the Switches and the dark gray, horizontal walls are the Platforms. There are two Switches with IDs that I'm setting as creation variables then overriding in the room editor to be "A" on the left and "B" on the right.

I think I understand what you are saying about GMS just picking one Switch instance and only checking that instance's array values. If an array is the wrong way to go, what would you recommend as an alternative? I'm down to nuke this whole thing and try a different approach if you have any suggestions.
 
I would assume it's this:
Code:
// if this platform has an ID that matches a switch that's flipped on...
if (obj_switch.hitArray[0] == ID) && (obj_switch.hitArray[1] = true) {
   active = true; // turn the platform on...
}

// if this platform has an ID that matches a switch that's flipped off...
if (obj_switch.hitArray[0] == ID) && (obj_switch.hitArray[1] = false) {
   active = false; // turn the platform off...
}
Try
Code:
// if this platform has an ID that matches a switch that's flipped on...
for (var i=0;i<instance_number(obj_switch);i++) {
   var switch_inst = instance_find(obj_switch,i);
   if (switch_inst.hitArray[0] == ID) && (switch_inst.hitArray[1] = true) {
      active = true; // turn the platform on...
   }

   // if this platform has an ID that matches a switch that's flipped off...
   if (switch_inst.hitArray[0] == ID) && (switch_inst.hitArray[1] = false) {
      active = false; // turn the platform off...
   }
}
You shouldn't use the object ID to check for a variable if multiple instances of that object exists.
 
Yeah, I thought the same thing, but apparently
Code:
show_debug_message("hitID = " + string(hitArray[0]));
show_debug_message("switchState = " + string(hitArray[1]));
was returning what they expected, so no idea what is going on. Perhaps they have that code in a collision event and are just doubling up on the collision check with the place_meeting for no reason whatsoever.
 

Papa Doge

Member
You shouldn't use the object ID to check for a variable if multiple instances of that object exists.
Bingo! Thanks a bunch, your explanation is really helpful too.

Why are you using other in your switch's code to set hit_array[0]? You aren't inside a with() call.
Oh, whoops. That's some old stuff I forgot to update. I used to have the code set up to change the state of the Platforms and Doors from the Switch's step event which was a lot more complicated. Thanks for pointing it out.
 
Top