Unreal Match 3 Grid Update Help!

I am using the new Unreal Match 3 learning template and I created a new custom tile, here is the blueprint from the tile.

Now, the tile is working as expected until it comes to the 3rd stage where the tile is destroyed. After the tile is destroyed this happens:

Is there any way of updating other tiles ( grid ) from blueprints, letting them know that there is no tile on that slot so they start filling the empty space ?

Thanks !

It is hard to be certain with this information, but I suspect that you probably want to use the Grid’s void ExecuteMatch(TArray MatchingTiles); to remove your tiles instead of simply destroying them.

To do that, you’d need to make that function BlueprintCallable. To do that, you’d need to open the Grid.h file and add the line UFUNCTION(BlueprintCallable, Category = Tile) just before the line declaring ExecuteMatch(…) (the line mentioned above):

	/** Execute the result of one or more matches. It is possible, with multiple matches, to have more than one tile type in the array. */
	UFUNCTION(BlueprintCallable, Category = Tile)
	void ExecuteMatch(TArray<ATile*> MatchingTiles);

From there, I think you can create a list (look for the Array Blueprint functions) of your tiles that are being removed and use the Tile’s Grid variable to call ExecuteMatch(…) with that list.

If this doesn’t do the trick, perhaps you can give us a little more information so we can better assist you. In particular, knowing the answers to these questions would help:

  • How are these tiles are currently being damaged?
  • What is the sequence of events that causes they are being removed/destroyed?

First of all thank you for your answer, I think you’re right. Probably I need to remove the tiles instead of destroying them.
I will try your suggestion and post another comment.

What I did is very simple, I took “Gem_Tile” blueprint and added radial damage “OnMatched” at actor location (Gem_Tile) with 20 Base Damage and Damage Radius od 50, just enough.

Now, I got this new tile Block_Tile_Static (the blueprint image is above in the first comment), which as you can see I have event “AnyDamage” and, changing the tile texture depending on the damage recieved from Gem_Tile which is working as I want it to work. The thing is as I explained in the first comment, the problem is on the third stage where I want the Block_Tile_Static to be Destroyed / Deleted instead of changing the texture. I’ve managed to destroy the actor but the grid is not responding, its like, there is a ghost tile there on that slot where the tile was destroyed.

Tell me if you need even more info or some screenshots and Thank you I really appreciate the help !

To add what actually is my main goal with no complications.

Block_Tile_Static is preventing swap so I want to destroy Block_Tile_Static when it takes more than 41 radial damage and I want the grid to respond to Block_Tile_Static being destroyed / deleted like when normal tiles are destroyed / deleted. To fall and fill the empty slot.

The part with the radial damage is resolved, the part with destroying / deleting the actor is where I get trouble !

That’s it :smiley:

O.K. I Am probably doing this wrong:

I will take a few hours off before I continue to work on this, this is my progress: I’ve managed to get it working like this but, when I damage two Block_Tile_Static at the same time or set a combo bomb off, the engine crushes. So, probably I can’t damage more than one Block_Tile_Static tile. Everything else is working fine, if I damage just one Block_Tile_Static, tile gets removed and the grid is working like it should.

Glad to hear of the progress!

At first glance that looks like what I was describing. I’ll have to take another look after a few hours off myself to make sure I’m not missing something obvious.

(At the moment, I’m slightly suspicious that the array may be of the wrong type, but I need to investigate a little more and double-check some of my “knowledge” before I’m sure either way.)

In the mean time, if you want to make it a little cleaner, you should be able to replace the “Get All Actors of Class” and “(Array) Get” nodes with self. That is, plugging self directly into the Target input on the Target/Grid node should perform at least as well as the one you showed above.

In any case, I’ll do a little more digging and let you know what I find.

Thank you, I will try that and some other things too. I will post my progress here.

Thanks again !

Seems like this is working a little bit better:

Now, I can damage more than one Block_Tile_Static, but, after playing a minute into the game I run into the same crush, especially when the bombs go off at full power.

Interesting!

Sounds like when multiple tiles were being destroyed, one would occasionally reference another when it should not have. That would at least explain the previous crash.

The current one sounds different though. I’ve tried to recreate the problem but without success so far. In my case, the tiles aren’t taking damage despite the radial damage being applied. However, when the tiles are matched (or when the level ends or the bombs are set off) the game handles it correctly.

Can you supply more information regarding the details of the crash? The call stack in particular tends to be helpful.

This is the main error of the crash when the bombs are going off:

Unknown exception - code 00000001 (first/second chance not available)

Assertion failed: !FallingTiles.Contains(NextTileUp) [File:F:\GameDevelopment\New folder\UnrealMatch3\Source\Match3\Grid.cpp] [Line: 473]

and I don’t quite understand on what you mean by call stack, sorry.

Thanks…

That is actually exactly enough.

The “Assertion failed” line tells us that the crash is in Grid.cpp, on line 473, when it checks that one of the tiles above the match is not yet in the list of falling tiles.

The problem is this: When the bombs explode, it causes gems to match. These matches make the tiles above them start falling and may also cause one or more Block_Tile_Static’s (especially below the initial match/es) to take damage and be destroyed. This, causes the Block_Tile_Static(s) to match which causes the tile(s) above to start falling.

The existing code from the Match 3 game expects all the matches to occur simultaneously. This allows it to check (also sometimes called “verify” or “assert”) that the tiles above any given matching tile are either included in the match or not yet falling. However, because your tiles execute additional matches at virtually the same time (but as part of separate ExecuteMatch(…) calls), this breaks the existing game’s check.

(More coming…)

Probably the simplest way to correct this is to change the existing code to stop making tiles fall when we find one that is already falling.

In Grid.cpp (line 469 for me) is this line:

	// If the tile above us is invalid or is being destroyed, stop adding to the list.
	if (NextTileUp && !MatchingTiles.Contains(NextTileUp))

Change it to this:

	// If the tile above us is invalid or is being destroyed, stop adding to the list.
	if (NextTileUp && !MatchingTiles.Contains(NextTileUp) && !FallingTiles.Contains(NextTileUp))

This will make it check that each tile above the match is not already falling. If a falling tile is found, it will stop making tiles above that fall (since it knows that any tiles above the falling one will also be falling).

We should also remove the assertion(/verification/check) that the tile is not in the list of falling tiles. To do that, just remove this line (from Grid.ccp, line 473 for me):
check(!FallingTiles.Contains(NextTileUp));

I hope this helps!

On a separate note, the “call stack” I referred to earlier is a programming term. Without going into the details, it tells very precisely what code was being executed at a particular time. In this case, what code was being executed at the time of the exception.

Traditionally, call stacks consist of a series of lines that specify a function (like Grid::ExecuteMatch), a file, and a line number. Some call stacks contain more information too.

The information you gave in the “Unknown exception” and “Assertion failed” lines is commonly (I think always for exceptions in the Unreal Engine) included at the top of a call stack.

Thank you for the help and explaining on the term “call stack”. I will make these changes you mentioned above and I will post back. Thanks again, this is the only thing stopping me from making this game. I can do everything else that I need with no problem.

Everything working as expected but, now seems to have another problem. This happens after the bombs explode and it seems this also happens when combo is activated I think:

Maaaan this turn out to be more complicated than I expected :D. There is no error or crushing, the game just stops, you can’t move the tiles beyond this point.

Doh! Of course I missed that. My apologies!

Changing the assumptions upon which code relies is always a somewhat tricky business, hence the complication.

I suspect that one or more of the Block_Tile_Static’s is still in the list of falling tiles when it is matched/destroyed. Since the game doesn’t spawn new tiles until all the existing tiles have finished falling and matched tiles wouldn’t finish falling, this would produce behavior like you are seeing.

If you want to verify this, you can make the FallingTiles list visible anywhere and check its contents when you hit this state. (eg. add a line UPROPERTY(VisibleAnywhere) just before the TArray FallingTiles; line in Grid.h. If it still contains tiles when you hit the problem, we can be pretty sure this is the cause.

There are a couple ways to fix it. Perhaps the cleanest is to remove any tiles that are being matched from the list of falling tiles. I’d recommend adding a couple lines shortly after the ones you changed before. In Grid.cpp (line 480 for me) is this line:

Tile->TileState = ETileState::ETS_PendingDelete;

I’d recommend adding these lines just before it:

// Remove the tile from the list of falling tiles if needed. Block_Tile_Static's can be marked as falling before matching if they are above and damaged by another match.
	if (Tile->TileState == ETileState::ETS_Falling)
	{
		check(FallingTiles.Contains(Tile));
		// We can remove just this single tile since we check that the tile is not in the list before adding it.
		FallingTiles.RemoveSingle(Tile);
	}

I did everything without any progress, tried with UPROPERTY(VisibleAnywhere) and there are no other tiles than the tiles that weren’t removed, same like the previous screenshot of the game. I’ve added those lines too, in Grid.cpp. However, the first time I tried the game after I added those lines in Grid.cpp I activated all bombs and the game was ok. The game freezes after I activated all bombs for the second time. Idk, strange. after that, The problem persisted whenever I activate all bombs.

Now while I was writing this I tried to play the game a few times more so I can see if I can notice something else and the same thing happened. First time game continued, second time game stopped. But, its not a rule, the game mostly stops at the first attempt at blowing all bombs at once and also the timer stops when this is happening.

Anyways, I will try some things and get back to you probably tomorrow. Thanks for the help, I really appriciate the help !

As I play more and more, I think that the radial damage is the problem. If I could manage to set only the gems ( candies ) to apply damage. Looks like the bombs and combos are already set to remove tiles. They are doing both right now, applying damage and removing tiles at the same time. I think that this is the real problem.

That sounds like a good way to look at the problem to me.

The problem is slightly more complex than you’ve stated though: When the existing code sets off the bombs, it collects a list of tiles (mostly gems, usually) that will be destroyed by the bomb explosions. It then performs a match on all the destroyed tiles. Your gems (always) cause damage when matched, which is why the bombs appear to cause damage and sometimes trigger this problem.

If you want to prevent damage when the bombs are going off, you’ll need to change the gem behavior to not apply the damage in that case. Something like this should work:

I think we are on the right track, now the bombs explode and just the bomb slots are empty :D. I Am trying out some stuff, that’s why I post this later that usual. I got few more things that I’d like to try.