Delete Multiple instances that are touching each other

L

Lemonz

Guest
Hello everyone! How are you today?

I am making a puzzle game that when you touch/click a colored block it will be destroyed, and all blocks of that same color would be destroyed that are touching the original block that was touch/clicked. I am trying to figure out the best way to destroy the blocks. Would this be something a collision detection would solve? or is this something that should happen during a step even or global button press? The mechanic is similar to games like Toy Blast and for the life of me I do not see any tutorials for that genre of game. When I search for puzzle tutorials I only find match 3 tutorials. Though the games are similar, they are not quite the same.

Could someone point me in the right direction on solving this issue? If I get this mechanic figured out I can continue building my prototype for my action puzzle game.
 

YoSniper

Member
Here's a quick way to do this.

Let's assume that your block object has a variable named my_color.

Then, you can say this.
Mouse Left Click Event
Code:
var this_color;
this_color = my_color;

with(object_index) {
    //The following code will get applied to every instance of this object, and this_color is treated like a global variable
    if my_color == this_color {
        instance_destroy();
    }
}
 
M

MrGreed

Guest
I am currently seeking answers to the same problem that Lemonz had posted here. I had tried the code that YoSniper had suggested.
It is good for destroying all of the blocks (objects) of the same color in the room.

However, we only want blocks that are adjacent to the clicked-on block of the same color to be destroyed.

The mini-game "Jam Kerblam" from LittleBigPlanet 2 is a good example of what I am trying to create.

I am also wondering on how I can have connected blocks of the same color to not be destroyed until all of their hit-points had been decreased to zero. Like how the blocks behave in the game Super Puzzle Platformer Deluxe.
 

NightFrost

Member
If you just need to affect adjacent blocks, you can collision detect with instance_place to cardinal directions and check through the retrieved id if their color-identifying variable matches.
 
This might be a little convoluted, but it's something I'm looking at to remove any collision detection. This kind of puzzle game works on a basic grid, so this simplifies it. Say, for example, that your blocks are 32 pixels in width and 32 pixels in height. Every block has two variables made in a create event:

x_row = x div 32; // div only returns how many times the number goes into the first value. So an object with 32 pixel width and a centered origin, with its x at 16, would return 'x_row = 0'
y_row = y div 32; // ^^^^^^
colour = whatever; // this is the only variable that may change throughout the course of the game

When you click on a block, and activate it, it then only needs to go through the other blocks and find what it's x_row, and y_row, is. And then find out if it's the same colour. I won't say for sure, but in theory this ought to be the simplest way to affect anything else. As there's no collision detection required, and would just use a basic WITH statement (called from the block you have clicked)

Code:
with (block)
{if colour == other.colour
{if x_row == other.x_row  && (y_row == other.y_row - 1 || y_row == other.y_row + 1)  // same x row, but is one above or below on the y row
{instance_destroy()}
if y_row == other.y_row  && (x_row == other.x_row - 1 || x_row == other.x_row + 1) // same y row, but is one to the left or the right on the x row
{instance_destroy()}}
}
The calling object wouldn't need to exclude itself, since it's looking for x_row and y_row values that it won't have. But anything to the left / right / above / below that has the same colour should destroy itself. I haven't put this to the test yet, but unless I've coded the above example wrong, can't see why it wouldn't work. And also be more efficient than the need to find specific instances through collision checks, or other similar tests.

EDIT: This works. I put this code in a mouse button event (mouse button released) as it limits the checks needed. When the button is released it see's which one has the mouse position within it's bbox boundaries, and that is the one that calls all the others
Code:
>>>>>>>>if ((mouse_x > bbox_left) && (mouse_x < bbox_right) && (mouse_y > bbox_top) && (mouse_y < bbox_bottom))
{ <<<<<<  //this is all uneccesary, as this mouse event checks for collision with instances. If it find s one, and it has this event, it will execute it.

with (block)
{if colour == other.colour
{if x_row == other.x_row  && (y_row == other.y_row - 1 || y_row == other.y_row + 1)  // same x row, but is one above or below on the y row
{instance_destroy()}
if y_row == other.y_row  && (x_row == other.x_row - 1 || x_row == other.x_row + 1) // same y row, but is one to the left or the right on the x row
{instance_destroy()}}
}
//}
 
Last edited:
M

MrGreed

Guest
Thanks for the code, the_dude_abides. It's a good start to what I am trying to solve. I had placed the code in a left mouse pressed event and had included one more line for also destroying
the block that was clicked on.
Code:
if ((mouse_x > bbox_left) && (mouse_x < bbox_right) && (mouse_y > bbox_top) && (mouse_y < bbox_bottom))
{with (block)
{if colour == other.colour
{if x_row == other.x_row  && (y_row == other.y_row - 1 || y_row == other.y_row + 1)  // same x row, but is one above or below on the y row
{instance_destroy()}
if y_row == other.y_row  && (x_row == other.x_row - 1 || x_row == other.x_row + 1) // same y row, but is one to the left or the right on the x row
{instance_destroy()}}
}
instance_destroy(); // destroy the block that was clicked on}
puzzleGame_problem_1.png puzzleGame_problem_2.png

In the first picture in the spoiler, I had clicked on the red block that was at the 11th row and 11th column.
That had only destroyed the red blocks that were one spot above, one spot below, one spot to the left, and one spot to the right of the block that was clicked on

Now, how can we have the other adjacent blocks of the same color (in this case, red) to be destroyed?
 
It's not quite the same as before, as I couldn't quite figure out how to extend the original idea. However, this works, so.... :) It might be more demanding by comparison, but in this kind of game I don't suppose it matters too much.

//create event
Code:
top = false;
bottom = false;
left = false;
right = false;
ignore = false;
// mouse button released event
Code:
left = true;
right = true;
top = true;
bottom = true;
ignore = true;
Since posting my previous code I have discovered that mouse button events are tested for collision with an instance (that has the event). This means that checking it's position is redundant, as it's part of the process. As long as the mouse is over it when the button is pressed, it will work. So that code has been removed :)

// step event
Code:
if ignore
{if left
{var is_left = instance_position(x - 32, y, obj_floor_parent); // obj_floor_parent is just what I've called the block object in my project. Replace this whatever you've called your block object
if is_left != noone
{if colour == is_left.colour
{with (is_left)
{left = true;
ignore = true;}}}}

if right
{var is_right = instance_position(x + 32, y, obj_floor_parent);
if is_right != noone
{if colour == is_right.colour
{with (is_right)
{right = true;
ignore = true;}}}}

if top
{var is_top = instance_position(x, y - 32, obj_floor_parent);
if is_top != noone
{if colour == is_top.colour
{with (is_top)
{top = true;
ignore = true;}}}}

if bottom
{var is_bot = instance_position(x, y + 32, obj_floor_parent);
if is_bot != noone
{if colour == is_bot.colour
{with (is_bot)
{bottom = true;
ignore = true;}}}}
instance_destroy();
}
Essentially - the first object clicked on tells those around it (if they are of the same colour) where they are in relation to it. Up / down / left / right, and they then seek out the one next to themselves in the same direction. They tell that one to look, and then destroy themselves.

The process repeats, unless the one next to it in the same direction is not the same colour, then it ends.

Using the collision checks is the only "intense" aspect of it (computation wise), otherwise I would say it's pretty straightforward how it works.

EDIT: The instance_position measurement of 32 will depend on how large your sprites are, and should be altered to reflect this.
 
Last edited:
M

MrGreed

Guest
Hey, the_dude_abides, what is the obj_floor_parent? How should I include that into this project? Do I need to make a visible and solid object
of that name and give it a 32 pixel wide, horizontal, rectangle sprite? And then place the obj_floor_parent object under the colored blocks in the room?
 
@MrGreed
My apologies - that is just the object I am using in my project to test this. Change that to whatever your block is called.

EDIT: I believe it's just 'block'. I forgot to change it when posting my code.

EDIT TWO: Ooops! I just looked at the video you included, and have misunderstood your intentions. I've been treating it as just in a straight line, whereas you want all connected blocks destroyed. With a bit more thought I'm sure I can figure that out.

EDIT THREE: Pretty simple - just remove some of the code. The basic checks are the same.

//step event
Code:
if ignore
{var is_left = instance_position(x - 32, y, block);
if is_left != noone
{if colour == is_left.colour
{with (is_left)
{ignore = true;}}}

var is_right = instance_position(x + 32, y, block);
if is_right != noone
{if colour == is_right.colour
{with (is_right)
{ignore = true;}}}

var is_top = instance_position(x, y - 32, block);
if is_top != noone
{if colour == is_top.colour
{with (is_top)
{ignore = true;}}}

var is_bot = instance_position(x, y + 32, block);
if is_bot != noone
{if colour == is_bot.colour
{with (is_bot)
{ignore = true;}}}

instance_destroy();
}
 
Last edited:
M

MrGreed

Guest
@the_dude_abides
I just wanted to say thank you for helping me with this problem. Your code works beautifully!
I hope you'll forgive me for not responding to you two months ago. I got side tracked by other stuff and ended up forgetting about this.

Anyway, I was wondering if you could help me with one more thing about this project.

What I am trying to include into your code for the step event is to have the same colored blocks that are connected to have their hit points be reduced by one.
The same colored blocks in a connection should only be destroyed if, at first, all of their hit points had been reduced to one. And then, when the player clicks on
that connection again, these same colored blocks that all have one hit point remaining should be destroyed. This behavior is similar to the blocks in the game
Super Puzzle Platformer Deluxe. You can observe this behavior in the second video that I had posted earlier in this page at the 1:20 mark. The player is
shooting at a chain of connected red blocks to have every block of that connection's hit points reduced down by one point.

I tried to do this myself, but the step event, when the player clicks on a connection of same colored blocks, the hit points of every block in the connection
is quickly decremented down to zero.
 
Top