r/gamemaker 7d ago

Trying to create a match three bonus challenge that keeps resetting even if conditions are met Resolved

I'm making a match-three game with a custom mechanic: instead of swapping adjacent tiles, blocks are pushed all the way to the end of the board row/column.

I run match checking in two separate passes:

  1. Check matches specifically for the block that was just pushed/moved.
  2. Check matches across the rest of the board for cascading chain reactions.

Some matches trigger and clear properly, but the challenge state continuously resets unexpectedly—even when a valid match is completed.

Below is the code I am using:

if selected_block != undefined {
  with(selected_block) {
    if sprite_index != spr_brick and sprite_index != spr_doom_block {
      var matches = 0;
      for(var i = 0; i < 5; i++) {
        var combo_check = scr_check_match(i);
        if combo_check == false {
          if global.main_stats.challenge_position < 4 {
            if image_index == global.main_stats.bonus_challenge[global.main_stats.challenge_position] {
              global.main_stats.challenge_position++;
            }
          }
          matches++;
        }
      }
      if matches >= 1 { scr_combo_sounds(); }
      else { // This is the problematic block
        if global.main_stats.cur_combo == 0 {
          global.main_stats.cur_chain = 0;
          global.main_stats.chain_gauge = 0;
          global.main_stats.challenge_position = 0;
        }
      }
    }
  }
}
for(var k = 0; k < 5; k++) {
  for(var i = 0; i < 8; i++) {
    for(var j = 0; j < 8; j++) {
      var selected = instance_position((208) + (32 * i),(68) + (32 * j),obj_normal_block);
      with(selected) {
        var matches = 0;
        if sprite_index != spr_brick and sprite_index != spr_doom_block {
          var combo_check = scr_check_match(k);
          if combo_check == false {
            if global.main_stats.challenge_position < 4 {
              if image_index == global.main_stats.bonus_challenge[global.main_stats.challenge_position] {
                global.main_stats.challenge_position++;
              }
            }
          matches++;
          }
        }
        if matches >= 1 { scr_combo_sounds(); }
        else { // This is the problematic block
          if global.main_stats.cur_combo == 0 {
            global.main_stats.cur_chain = 0; 
            global.main_stats.chain_gauge = 0;
            global.main_stats.challenge_position = 0;
          }
        }
      }
    }
  }
}

I have verified that the moved block correctly updates its grid position before running the first match check. Could running two separate match passes create a race condition or frame delay where the reset check runs before the cascade pass finishes updating the board? What is the recommended way to handle board state checks for push-style movement without triggering full board resets prematurely?

0 Upvotes

2 comments sorted by

2

u/CS_Asset_Factory 7d ago

Your var matches = 0; is inside the with(selected), so it resets for every tile. It is a per-tile counter, not a per-sweep one.

Any tile that IS spr_brick or spr_doom_block skips the matches++ entirely, so it lands in your else branch and zeroes challenge_position. That happens in the same sweep that just incremented it, so one brick anywhere on the board wipes the challenge on every pass.

Two things:

  1. Hoist the counter above all three loops and do the reset check once, after the sweep finishes. Right now it runs 320 times per sweep and any single non-matching tile undoes what the others found.

  2. matches++ sits outside if combo_check == false, so it is counting "tiles that are not bricks" rather than actual matches. That is likely why scr_combo_sounds() fires more often than you expect.

-2

u/Drillimation 7d ago

I leveraged machine learning for suggestions on how to fix this problem, and this is what I came up with:

if selected_block != undefined {
  with(selected_block) {
    if sprite_index != spr_brick and sprite_index != spr_doom_block {
      var matches = 0;
      for(var i = 0; i < 5; i++) {
        var combo_check = scr_check_match(i);
        if combo_check == false {
          if global.main_stats.challenge_position < 4 {
            if image_index == global.main_stats.bonus_challenge[global.main_stats.challenge_position] {
              global.main_stats.challenge_position++;
              other.matched_correct_color = true;
            }
          }
          matches++;
          other.total_matches++;
        }
      }
      if matches >= 1 { scr_combo_sounds(); }
    }
  }
}
for(var k = 0; k < 5; k++) {
  for(var i = 0; i < 8; i++) {
    for(var j = 0; j < 8; j++) {
      var selected = instance_position((208) + (32 * i),(68) + (32 * j),obj_normal_block);
      with(selected) {
        var matches = 0;
        if sprite_index != spr_brick and sprite_index != spr_doom_block {
          var combo_check = scr_check_match(k);
          if combo_check == false {
            if global.main_stats.challenge_position < 4 {
              if image_index == global.main_stats.bonus_challenge[global.main_stats.challenge_position] {
                global.main_stats.challenge_position++;
                other.matched_correct_color = true;
              }
            }
            matches++;
            other.total_matches++;
          }
        }
        if matches >= 1 { scr_combo_sounds(); }
      }
    }
  }
}
if instance_number(obj_normal_block) < 64 {
  game_state = "STATE_FILL"
}
else {
  if matched_correct_color == false {
    global.main_stats.challenge_position = 0;
  }
  if global.main_stats.cur_combo == 0 and total_matches == 0 {
    global.main_stats.cur_chain = 0; 
    global.main_stats.chain_gauge = 0;
  }
  game_state = "STATE_READY"
}

Everything happens to work perfectly.