Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Advertisement

[HELP] Column 6 Not Merging + Bottom Row Merge from Preview Not Working (7x7 Merge Grid with Upward Gravity)

Started by April 21, 2025 02:39 PM
1 comment, last by Alberth 5 days, 1 hour ago

Hi everyone,

I’m building a 2D merge puzzle game in Unity and have hit two problems I can’t seem to solve, despite trying everything from logging and inspector debugging to rewrites and export comparisons.

I’m hoping someone with a fresh perspective can help spot the issue(s).

Game Overview:

Grid: 7x7 (TileSlot_00 to TileSlot_48)

Gravity: Upward – Bricks drop to the bottom, but merge upward

Bricks: Merge when two of the same value meet (triangular number progression)

Preview System: One brick shows at a time, player taps a column to drop it in

Ghost Row: Used to allow merging when the grid is full – positioned under bottom row (GhostTile_00 to GhostTile_06)

Problem 1: Column_6 Not Merging

Every column (0–5) works correctly. Column_6 (index 6) accepts bricks, but refuses to merge, even if two same-value bricks are stacked.

Here’s what I’ve verified:

Column_6 is populated correctly in the inspector

BrickPlacer.cs logs the correct placement

MergeManager.cs runs, but mergeGroup.Count never exceeds 1 for Column_6

FindMergeGroup() does not detect neighboring bricks in this column

No different settings in the tiles, anchors, hierarchy, or components

All TileSlots in Column_6 are named correctly: TileSlot_06, TileSlot_13, etc.

Problem 2: Bottom Row Won’t Allow Merge from Preview When Full

When the board is full, I want the game to allow merging with a bottom row brick (e.g., drop a matching value directly into TileSlot_43).

To support this:

Ghost tiles are added: GhostTile_00 to GhostTile_06, placed just below the grid and mapped per column

Ghost tiles are assigned in ColumnManager.cs via a GhostRow list

GameStateManager.cs checks them in game-over conditions

BrickPlacer.cs checks them when placing a new brick if the column is full

Despite all that:

Merges don’t happen when placing a preview brick directly onto the ghost tile

Ghost tiles show multiple children after repeated use (bricks stacking instead of merging)

FindMergeGroup() does not include the adjacent bottom brick when starting from ghost tile

Code Example: Bottom Merge Attempt

In BrickPlacer.cs, here’s how I attempt the ghost merge logic:

Transform ghost = columnManager.GetGhostTileForColumn(columnIndex);

if (ghost != null && columnManager.IsTileOccupied(ghost)) {

GameObject ghostBrick = columnManager.GetBrickOnTile(ghost);

if (ghostBrick.GetComponent<MergeBlock>().GetValue() == previewValue) {

GameObject placed = previewManager.UseCurrentBrick();

PlaceBrick(placed, ghost, columnIndex);

return;

}

}

But this leads to overlap, not a merge.

Debugging Done So Far:

Rewritten MergeManager.cs, BrickPlacer.cs, ColumnManager.cs, and GameStateManager.cs from scratch

Validated ghost tiles are in hierarchy and mapped 1:1 with columns

Ghost tiles are being clicked and logged, but not causing merges

Tested merge detection with debug logs – ghost tiles never show as neighbors

Exported full scene hierarchy to CSV to confirm correct assignments

Verified tile names: TileSlot_00 through TileSlot_48 and GhostTile_00 to GhostTile_06

What I Need Help With:

Why won’t Column 6 merge?

  • All other columns work. The logic is identical.
  • Why doesn’t the ghost row support merges with the bottom row?
  • Merges should be valid between preview → ghost → bottom tile above.

Scene Setup:

GridContainer has 49 tiles (TileSlot_00 to TileSlot_48)

GhostTileContainer sits below GridContainer with GhostTile_00 to GhostTile_06

All tiles are 130x130 with 2x2 spacing

Game uses a custom upward merge logic via MergeManager.cs

Willing to Provide:

  • Full zipped project scripts
  • Scene hierarchy screenshots or exports
  • Logs or test scenes

Thanks for reading – any help is massively appreciated.

I don't know unity, and don't really understand the terms that you use, but I do have experience in debugging. Hopefully you can use the general approach that I describe below.

I don't know what you did exactly, but with these problems, you generally have to go down to code line level at least. Within a line of code, you need to check what values are used, etc. In other words, does the computer do what you think it should do?

The above is very high detail, and you don't want to do that with all your code (it would take forever). The general approach is to first reduce the problem as much as possible. Then first find out whether the correct code is executed, and then whether the values that are used are correct.

Reducing your test case:

  • If you didn't do it already, make a backup of your work before you make changes to find the bug. (A version control system is great for this). This gives you the option to make any change in the code, since you know the original code is safely stored.
  • Don't bother about other columns, just pick 1 column for debugging. They all have the same behavior, so likely the problem is the same everywhere. (You can only find out after fixing one of them.)
  • You may want to reduce the number of rows (depending on how easy that is), you only need 2 rows for testing, perhaps 3 if dropping is also part of the problem. Having more isn't a problem but it means you execute more code and thus more can go wrong. Tests can be slower, you may get more log output, etc etc.
  • Similarly, You need just 2 bricks. One should be at the bottom, and the other one drop in from (I guess) column 4 into 5. (Basically, make the case as small as possible in any way you can think of.)

Assuming the test is quick, do many small experiments. There are 2 things you want to find out: The first thing is to find the spot where it makes the wrong turn. (Code follows the wrong path. An ‘if’ is not taken, a ‘while’ is skipped, etc.) The second thing is to find why it makes the wrong decision.

Do an experiment after each change, to check that the problem didn't suddenly disappear and to get more information.

For finding the spot where it makes a wrong turn, single stepping through the function with a debugger is generally the best option. Without it, just log if the code reaches some point that you expect. If it does what you expect, the spot must be further away in the code. If it doesn't match your expectations, the spot is earlier in the code. Basically this allows you to either ensure the code reaches all statements that you expect, or you find a spot where the code does something you don't expect. Eg an ‘if’ condition isn't taken, a loop iteration is skipped, etc.

After an experiment, update or extend the debugging code that takes what you just learned into account. If your log is unexpectedly empty, the code never got to that point, so add logging earlier, for example. If the log shows what you expect, add more logging further down. You know the code will take a wrong turn, it's just a matter of finding where.

Once you got the spot of the bad turn, start digging **why** it happens. Log values of things. If eg the first ‘if’ in the above merge code fails, is that because of ghost != null or because of columnManager.IsTileOccupied(ghost) ? If the second condition, does ‘ghost' have the expected value? If not, why not? If it does, why does `IsTileOccupied’ give the wrong answer?

Good luck with your hunt for the bug!

Advertisement
Advertisement
Advertisement