- Home /
Change Block Position In Block Matching Game C#
Hey everyone! Back with another question about my block matching game. I've got the functionality of destroying blocks, adding points based off blocks destroyed, and I'm getting close to full functionality. The last thing that I'm really trying to accomplish is actually being able to MOVE the blocks down after a section of blocks is destroyed. I'll attach the code I have working so far but unfortunately not accomplishing anything I want. I'll also attach a few pictures which will show you what I'm attempting to accomplish. Thanks for your help in advance!
public void applyGravity(GameObject clickedBlock) {
Vector2 altBlockPos = GetBlockPos(clickedBlock);
// Keeps track of empty block Positions
int emptyBlockCount = 0;
//List to store blocks that are found before they are dropped down
List<Block> foundBlocks = new List<Block>();
//Vector2 newBlockPos;
for (int x = 0; x < 10; x++) {
for (int y = 0; y < 10; y++) {
// Find empty spaces going up
if (altBlockPos.y > 0) {
if (grid[(int)altBlockPos.x,(int)altBlockPos.y-1].renderer.material.color == null) {
Debug.Log ("Found Empty Block At Position: " /*Display empty block position*/);
altBlockPos.y -= 1;
}
}
// Find empty spaces going right
if (altBlockPos.x > 0) {
if (grid[(int)altBlockPos.x-1,(int)altBlockPos.y].renderer.material.color == null) {
altBlockPos.x -= 1;
}
}
// Find empty spaces going down
if (altBlockPos.y < grid.GetLength(1)-1) {
if (grid[(int)altBlockPos.x,(int)altBlockPos.y+1].renderer.material.color == null) {
altBlockPos.y -= 1;
}
}
// Find empty spaces going left
if (altBlockPos.x < grid.GetLength (1)-1) {
if (grid[(int)altBlockPos.x+1,(int)altBlockPos.y].renderer.material.color == null) {
altBlockPos.x -= 1;
}
}
}
}
}
In the second image, I want all the blocks that are above those empty space to be moved down and for their previous location to be saved as empty locations.
Answer by RudyTheDev · Feb 19, 2014 at 04:59 PM
Replace for loops with:
// Go through every column
for (int x = 0; x < 10; x++)
{
// Keep track of how high this column's block tower is
int lastEmptyPos = 0; // default = 0 -- no blocks yet
// Go through every row, bottom-up
for (int y = 0; y < 10; y++)
{
// If the current block isn't empty
if (grid[x, y].renderer.material.color != null)
{
// If the last tower height we had is lower than our position (there have been gaps)
if (lastEmptyPos < y)
{
// The drop the block down
grid[x, lastEmptyPos].renderer.material.color = grid[x, y].renderer.material.color;
grid[x, y].renderer.material.color = null;
}
// Since we have a block (regardless if we moved it), the tower must be +1 higher
lastEmptyPos++;
}
// If there is no block, we don't increase lastEmptyPos
}
}
This compiles for the most part, but it won't run properly because it keeps telling me that "The result of comparing value type 'UnityEngine.Color' with null is 'true'. So, when I attempt to run it, it doesn't actually do anything for some messed up reason.
I copy-pasted that part from your code and used bool
s in my test. I'm guessing material color is never null, but transparent of white or whatever value you are using for when it is "not a block".
If I were doing this, I would hide/show the GameObjects (`SetActive(true/false)`) ins$$anonymous$$d of removing their color and check activeSelf
ins$$anonymous$$d.
Ohhhhh I got ya. Ok...well everything seems to compile just fine and the only issue now is that when I click on a block, it basically destroys everything above that block. I'll post a picture for example. I'm betting that there's just a few tweaks to be made with the code, but I can't seem to strike where exactly it's messing up
For reference, I clicked on the Green blocks that are on the right side and in the 3rd row. I went for those because I figured it'd be simple enough to click those and move them down, this is what happened afterwards,
$$anonymous$$y belief is that because of the way it's being called, it's pushing through all of the grid to the left and right and eli$$anonymous$$ating all of the Blocks and then shifting them down...I think? I could be wrong though. I'll throw a stop in the code so that I can see what's happening. If you think of anything, let me know. Thanks again $$anonymous$$, you're of fantastic help!
That's weird...
Which way do your grid coordinates go? In my code, X goes right and Y goes "up" (blocks fall to lower indices). Although, this shouldn't matter. Where and when do you call applyGravity()
?
I'm calling applyGravity() in the function that destroys blocks. And yeah I switched those in my code because my scene is set up different than normal games unfortunately haha but my X and Y are switched up.
Answer by SlyyGuyy · Feb 20, 2014 at 09:37 PM
#region Destroy Blocks
public int DestroyBlock(GameObject clickedBlock) {
// Counter to keep track of destroyed blocks
int blocksDestroyed = 0;
// Counter keeps track of Confetti Points
int blockConfettiPoints = 0;
Vector2 blockPos = GetBlockPos(clickedBlock);
if (blockPos != new Vector2(-1,-1)) {
Color texType = clickedBlock.renderer.material.color;
clickedBlock.renderer.material.color = Color.clear;
blocksDestroyed++; // Count up blocks as 1 block is destroyed
// Destroy blocks moving up
if (blockPos.y > 0) {
if (grid[(int)blockPos.x,(int)blockPos.y-1].renderer.material.color == texType) {
blocksDestroyed += DestroyBlock(grid[(int)blockPos.x, (int) blockPos.y - 1]);
}
}
// Destroy blocks going right
if (blockPos.x > 0) {
if (grid[(int)blockPos.x-1,(int)blockPos.y].renderer.material.color == texType) {
blocksDestroyed += DestroyBlock(grid[(int)blockPos.x-1, (int) blockPos.y]);
}
}
// Destroy blocks going down
if (blockPos.y < grid.GetLength(1)-1) {
if (grid[(int)blockPos.x,(int)blockPos.y+1].renderer.material.color == texType) {
blocksDestroyed += DestroyBlock(grid[(int)blockPos.x, (int) blockPos.y + 1]);
}
}
// Destroy blocks going left
if (blockPos.x < grid.GetLength (1)-1) {
if (grid[(int)blockPos.x+1,(int)blockPos.y].renderer.material.color == texType) {
blocksDestroyed += DestroyBlock(grid[(int)blockPos.x+1, (int) blockPos.y]);
}
}
}
// Add confetti points
switch(blocksDestroyed) {
case 2:
blockConfettiPoints += 4;
break;
case 3:
blockConfettiPoints += 8;
break;
case 4:
blockConfettiPoints += 12;
break;
case 5:
blockConfettiPoints += 16;
break;
case 6:
blockConfettiPoints += 20;
break;
case 7:
blockConfettiPoints += 24;
break;
case 8:
blockConfettiPoints += 28;
break;
case 9:
blockConfettiPoints += 32;
break;
case 10:
blockConfettiPoints += 36;
break;
case 11:
blockConfettiPoints += 40;
break;
case 12:
blockConfettiPoints += 44;
break;
case 13:
blockConfettiPoints += 48;
break;
}
totalConfetti += blockConfettiPoints;
//This point system doesn't make much sense at all
//if 2 blocks match +4 points
//if 3 blocks match +9 points
//if 4 blocks match +16 points
//if 5 blocks match +25 points
//if 6 blocks match +36 points
//if 7 blocks match +49 points
//if 8 blocks match +64 points
Debug.LogError ("Blocks Destroyed: " + blocksDestroyed);
//Debug.LogError ("Confetti Points Earned: " + blockConfettiPoints);
Debug.LogError ("Total Confetti Points: " + totalConfetti);
applyGravity(clickedBlock);
return blocksDestroyed;
}
#endregion
#region Apply Gravity
public void applyGravity(GameObject clickedBlock) {
// Go through every column
for (int x = 0; x < 10; x++) {
// Track empty positions in the colum
int lastEmptyPos = 0;
// Go through every row, starting from the bottom
for (int y = 0; y < 10; y++) {
// Check to see that the current block is not empty
if (grid[x, y].renderer.material.color != Color.clear) {
// Check for gaps
if (lastEmptyPos < x) {
// Drop the blocks down
grid[lastEmptyPos, y].renderer.material.color = grid[x, y].renderer.material.color;
grid[x, y].renderer.material.color = Color.clear;
}
// Since we have a block (regardless if we moved it), the tower must be +1 higher
lastEmptyPos++;
}
}
}
}
}
#endregion
See, yes, that's the problem I guessed. You are calling applyGravity(clickedBlock);
inside DestroyBlock()
. This means every time DestroyBlock()
calls more DestroyBlock()
s, applyGravity()
is called again, as many times. You need to call DestroyBlock()
, then call applyGravity()
after. (Same would be true for counting confetti points after, not inside recursion, but there you don't see any problems, because only the last score ends up mattering.)
Also, in applyGravity()
you need to do y
loop first and x
loop second (just swap the two around), if your columns are actually along x axis. It's not enough to swap [lastEmptyPos, y]
order and compare with (lastEmptyPos < x)
, because int lastEmptyPos = 0;
is still defined before y loop, although it's supposed to be counting progress along x
.
P.S. A good trick of coding is to make your game width and height different, so if there are any problems with coordinates, you spot them immediately. But if both are 10, you could be calling wrong ones and it still "runs".
Oh my goodness do I feel silly. Thank you so much for your help! It works perfectly now phew