Legacy GM Bubble Shooter Game

M

Matt93

Guest
I'm trying to draw up a prototype of a bubble shooter game for touch screen devices.

I've managed to set up the bubbles to shoot wherever you tap and release on the screen. That's working fine. So far I'm only working with bubbles of one colour, to get to grips with the mechanics.

I'm really stuck on how to get the bubbles to destroy any of the same colour which they are shot into. The initial room is set up with a few static bubbles already touching. If these are hit with a 'moving' bubble, these, as well as the moving bubble, will all need to be destroyed. I think I must need an array to do this, but I'm not sure what to do.

When I add new colours of bubble, will I also need to put the bubbles into an array for organisation?

Any help and advice would be great, I've been working at this for hours!

Cheers!
 
T

TDSrock

Guest
There are two ways that I see.
One is use an array.
Pro's: This makes finding the data about the other bubbles easy, which is also going to be faster then the alternative.
cons: Your world will have to follow an array formation of some kind not a real problem if you want to be similar to the traditional bubble shooter games but with the current computing power, I love to see one of these come out where the bubble stays where I shot it, instead of aligning itself with the closest array slot that I slammed it towards.

Two is use a recursive function to find all instances of same colored bubbles in range
Pro's: The world is not bound to match an array.
Cons: Much, much more difficult for the programmer to create.

Now I've never made a bubble shooter myself so the second route would be pure theoretical on my end whereas the first one is just matching array data properly.

The most difficult script here is going to find out how many bubbles a bubble is touching of the same kind.(I think that almost always needs to be a recursive script)
 
M

Matt93

Guest
There are two ways that I see.
One is use an array.
Pro's: This makes finding the data about the other bubbles easy, which is also going to be faster then the alternative.
cons: Your world will have to follow an array formation of some kind not a real problem if you want to be similar to the traditional bubble shooter games but with the current computing power, I love to see one of these come out where the bubble stays where I shot it, instead of aligning itself with the closest array slot that I slammed it towards.

Two is use a recursive function to find all instances of same colored bubbles in range
Pro's: The world is not bound to match an array.
Cons: Much, much more difficult for the programmer to create.

Now I've never made a bubble shooter myself so the second route would be pure theoretical on my end whereas the first one is just matching array data properly.

The most difficult script here is going to find out how many bubbles a bubble is touching of the same kind.(I think that almost always needs to be a recursive script)
Thank you for your reply. I think I'll go down the first route for now. So how do I go about creating that array in code? Would I have to divide the room up into a grid?
 
T

TDSrock

Guest
Think a tad more abstract.

You make the array, fill it up with data and then draw the array using double for loops.

EDIT: I've jumped into my old tetris project for you to grab an example of where I have an array with data in it, and I draw it to the screen.
Code:
for (int i = 0; i < this.Width; i++)
        {
            for (int j = 0; j < this.Height; j++)
            {
                blockPosition = new Vector2(i * gridblock.Height, j * gridblock.Width);
                switch (gridArray[i, j])
                {
                    case 0:
                        s.Draw(gridblock, Vector2.Add(blockPosition, position), Color.White);
                        break;
                    case 1:
                        s.Draw(gridblock, Vector2.Add(blockPosition, position), Color.Yellow);
                        break;
                    case 2:
                        s.Draw(gridblock, Vector2.Add(blockPosition, position), Color.CornflowerBlue);
                        break;
                    case 3:
                        s.Draw(gridblock, Vector2.Add(blockPosition, position), Color.Purple);
                        break;
                    case 4:
                        s.Draw(gridblock, Vector2.Add(blockPosition, position), Color.Orange);
                        break;
                    case 5:
                        s.Draw(gridblock, Vector2.Add(blockPosition, position), Color.Blue);
                        break;
                    case 6:
                        s.Draw(gridblock, Vector2.Add(blockPosition, position), Color.Green);
                        break;
                    case 7:
                        s.Draw(gridblock, Vector2.Add(blockPosition, position), Color.Red);
                        break;
                    default:
                        Console.WriteLine("Draw default");
                        break;
                } 
            }
            TetriminosGrid.Draw(gameTime, s);
            InPlayGrid.Draw(gameTime, s);
        }
 
T

TDSrock

Guest
Please could you give me some pointers with code?
Just added an example from C#. most the things there will be valid in GML besides vector2 related things I reckon.
Just so you get it though. the vector2 that says position is simply an x and then a y coordinate.

The draw function used there (s.draw) is one we had to make ourselves though as what we worked in diden just do that part for us, Here's what it takes: < name of an image; a position; a color>
 
M

Matt93

Guest
Just added an example from C#. most the things there will be valid in GML besides vector2 related things I reckon.
Just so you get it though. the vector2 that says position is simply an x and then a y coordinate.

The draw function used there (s.draw) is one we had to make ourselves though as what we worked in diden just do that part for us, Here's what it takes: < name of an image; a position; a color>
Thank you. Could I also use a ds_grid for this?
 
T

TDSrock

Guest
Yeap, a ds grid and a 2 dimensional array are the same datatype, however the ds_grid has some things built for you ready to be used.
 
M

Matt93

Guest
Yeap, a ds grid and a 2 dimensional array are the same datatype, however the ds_grid has some things built for you ready to be used.
Okay great, I'm trying to use a ds_grid. I still don't completely understand though. Are the bubbles supposed to snap to the value in the grid?
 
T

TDSrock

Guest
Think of the play area with a grid on-top of it. Each index in the array represents one of those slots. The moment a bubble lands there is an array slot that is closest to where the bubble landed. As-long as that slot isn't already filled, the new bubble should pop into that place.
 
M

Matt93

Guest
Think of the play area with a grid on-top of it. Each index in the array represents one of those slots. The moment a bubble lands there is an array slot that is closest to where the bubble landed. As-long as that slot isn't already filled, the new bubble should pop into that place.
Yes that makes sense! I understand the logic now. If I'm using a ds_grid, is there code to check which slot is nearest though? I've been looking through the documentation and can't seem to find anything. Thank you so much for your help with this by the way.
 
T

TDSrock

Guest
Nope unfortunately not, You'll have to come up with that piece on your own(or with aid from me and others on this website).

The baseline is though you know the position of where the bubble lands and you know what position each index on the ds_grid represent. Armed with that knowledge you can check every position within a certain range of the bubble.
 
M

Matt93

Guest
Nope unfortunately not, You'll have to come up with that piece on your own(or with aid from me and others on this website).

The baseline is though you know the position of where the bubble lands and you know what position each index on the ds_grid represent. Armed with that knowledge you can check every position within a certain range of the bubble.
Ah okay, now I'm really stuck then. I'm thinking I could store the x and y coordinates of where each bubble lands. But then I have no idea how to map these onto a grid?
 
T

TDSrock

Guest
Well ahead of time you decide what x and what y coordinate map to the ds_grid

Example:
First I chose that [0][0] the top left slot is going to be at x = 10 y = 10
The from there each block will get 32 pixels of space.
so in a double for loop I can map each x and y quite easily.

Code:
for(x=0; x<width;x++){//width represents the number of blocks in the width
   for(y=0; y<height;y++){
      X_LocationOfIndex[x][y] = 10 + 32 * x;
      Y_LocationOfIndex[x][y] = 10 + 32 * y;
   }
}
 
M

Matt93

Guest
Well ahead of time you decide what x and what y coordinate map to the ds_grid

Example:
First I chose that [0][0] the top left slot is going to be at x = 10 y = 10
The from there each block will get 32 pixels of space.
so in a double for loop I can map each x and y quite easily.

Code:
for(x=0; x<width;x++){//width represents the number of blocks in the width
   for(y=0; y<height;y++){
      X_LocationOfIndex[x][y] = 10 + 32 * x;
      Y_LocationOfIndex[x][y] = 10 + 32 * y;
   }
}
Thank you! I'll try this out. Would X_LocationOfIndex[x][y] and Y_LocationOfIndex[x][y] be variables I'd have to define in the create event? So I assume I can just define them as 0?
 
T

TDSrock

Guest
That for loop is one you can run in the create event. After you define what width and height are.
 
M

Matt93

Guest
That for loop is one you can run in the create event. After you define what width and height are.
Okay, I've now put that in my control object's create event. So when the bubble lands, do I just map its x and y onto the nearest locationofindex?
 

FrostyCat

Redemption Seeker
Geez, why waste time with a big, fat and redundant lookup array when just two simple divs would have sufficed?

Using the same (10, 10) top-left setup with 32x32 squares:
Code:
grid_x = (x - 10) div 32;
grid_y = (y - 10) div 32;
At the beginning of the game, set up a grid or 2D array representing your playing field. When a bubble lands, use the two lines above to get which cell it belongs to, then set that entry in the grid to a value representing the bubble's colour.
 
M

Matt93

Guest
Thank you both of you. I have now managed to get the bubbles to generate at room start, and any I launch also snap to the grid. Here's my code:

Code:
Obj_control Create event

for(x=0; x<width;x++){//width represents the number of blocks in the width
   for(y=0; y<20;y++){
      global.X_LocationOfIndex[x,y] = 80 + 32 * x;
      global.Y_LocationOfIndex[x,y] = 40 + 32 * y;
   }
}
Code:
Obj_control draw event:

for(i=0; i<width;i++){//width represents the number of blocks in the width
   for(j=0; j<height;j++){
      draw_sprite(spr_bubble_blue,0,global.X_LocationOfIndex[i,j],  global.Y_LocationOfIndex[i,j]) 
   }
}
Code:
Obj_bubble step:

if (distance_to_point(global.target_x, global.target_y) < 5)
{
    speed = 0;
    x = global.X_LocationOfIndex [(x-80) div 32, 2]
    y = global.Y_LocationOfIndex [2, (y - 40) div 32 ]


    instance_destroy();
    instance_create(x,y,obj_bubble_fixed);
As you can see, at the moment, I only have one colour of bubble. Now I'm just trying to get my head around detecting bubbles of the same colour, (or for now, any other connected bubbles) and when there are 3 or more of these, destroying all the ones in the chain. I think I would have to do this recursively (as you told me earlier, TDSrock). Any pointers as to how to go about this, as well as help with the code, would be really great. I think maybe checking two slots above, below and diagonally may be a starting point for this? And setting all the slots which contain a bubble sprite to a value? I'm determined to do this! Cheers.
 
Last edited by a moderator:
T

TDSrock

Guest
What I would do to start is add a flag (Boolean) to all the bubbles called checked and a flag (Boolean) called sameAs.
Code:
//create event parent obj of bubbles
checked = false;
sameAs = false;
Then I would device a script that checks each index around a chosen index. If the index holds a bubble lets ask that bubble if it has already been checked before, if so, ignore it. If not, check it, and set checked flag to true. If it is the same color set his sameAs flag to true.
if the sameAs flag is flipped we need to run the same script on the new bubble(thats the recursive part). So if you were to say diagnals are impossible this script will sometime run 2 times after the first time.

Here's an example. Note that this code won't be ideal and won't just work but the main idea I hope comes across.

Code:
/*
* param 0: x coordinate
* param 1: y coordinate
* param 2: color representation int
*/
var x = argument[0];
var y = argument[1];
var color = argument[2];

// I like to immediately set my parameters to var's in scripts where I know the script will be it's own contained unit that should NOT have an impact on the object that it gets ran in.

for(var x_offset = -1; x_offset < 1; x_offset++){
   for(var y_offset = -1; y_offset < 1; y_offset++){
      //Double for loop will aid us in looking into all indexes around us(this will also check ourselves though which we can skip
      if(!(x_offset == 0 && y_offset == 0)){
         //So now anything in here will check all indexes around the giving index I'll leave this part blank for you to fill in on your own ;)
      }
   }
}
That should help you on your way.
 
M

Matt93

Guest
What I would do to start is add a flag (Boolean) to all the bubbles called checked and a flag (Boolean) called sameAs.
Code:
//create event parent obj of bubbles
checked = false;
sameAs = false;
Then I would device a script that checks each index around a chosen index. If the index holds a bubble lets ask that bubble if it has already been checked before, if so, ignore it. If not, check it, and set checked flag to true. If it is the same color set his sameAs flag to true.
if the sameAs flag is flipped we need to run the same script on the new bubble(thats the recursive part). So if you were to say diagnals are impossible this script will sometime run 2 times after the first time.

Here's an example. Note that this code won't be ideal and won't just work but the main idea I hope comes across.

Code:
/*
* param 0: x coordinate
* param 1: y coordinate
* param 2: color representation int
*/
var x = argument[0];
var y = argument[1];
var color = argument[2];

// I like to immediately set my parameters to var's in scripts where I know the script will be it's own contained unit that should NOT have an impact on the object that it gets ran in.

for(var x_offset = -1; x_offset < 1; x_offset++){
   for(var y_offset = -1; y_offset < 1; y_offset++){
      //Double for loop will aid us in looking into all indexes around us(this will also check ourselves though which we can skip
      if(!(x_offset == 0 && y_offset == 0)){
         //So now anything in here will check all indexes around the giving index I'll leave this part blank for you to fill in on your own ;)
      }
   }
}
That should help you on your way.
Thank you so much! I'm still trying to wrap my head round this code, but think I'm getting there. I have now added a variable in to check whether an index is filled:

Code:
for(i=0; i<width;i++){//width represents the number of blocks in the width
   for(j=0; j<20;j++){
      global.X_IndexFilled[i,j] = -1 //empty slot
      global.Y_IndexFilled[i,j] = -1 //empty slot
   }
}
Then in the draw event, made sure only the slot with a sprite drawn is set to 1:

Code:
for(i=0; i<width;i++){//width represents the number of blocks in the width
   for(j=0; j<height;j++){
      draw_sprite(spr_bubble_blue,0,global.X_LocationOfIndex[i,j],  global.Y_LocationOfIndex[i,j])
      global.X_IndexFilled[i,j] = 1; //sets index with sprite to full
      global.Y_IndexFilled[i,j] = 1;  
   }
}
and made sure the slots which new bubbles are added to are set to 1:
Code:
Bubble step:

if (distance_to_point(global.target_x, global.target_y) < 5)
{
    speed = 0;
    x = global.X_LocationOfIndex [(x-80) div 32, 2]
    y = global.Y_LocationOfIndex [2, (y - 40) div 32 ]
    global.X_IndexFilled[(x-80) div 32, 2] = 1;
    global.Y_IndexFilled[2, (y - 40) div 32]  = 1;
I'm still not quite sure how to loop through all the indexes though. I understand that the logic is: loop through slots, if slot is empty go to next one (would this be both horizontally and vertically?), if slot is full, check adjacent bubbles, if there are adjacent bubbles of the same colour, loop through again. Is that right? I was just confused about why there were x_offset and y_offset in that sample code you wrote? I'm really sorry to ask this, as I prefer working things out for myself, but is there any chance you could tell me a script you would write to do this please? Using my variables if possible? It just might help to see how to do it, then map the logic onto it. I have been through scripts in other languages, and just still don't understand how to do it.
 
Last edited by a moderator:
T

TDSrock

Guest
I'll extend what I wrote down a little bit. That should make it more clear. I actually intended to write what I am going to add now originally but mid writing forgot to :p

Code:
/*
* script name: scr_Check_Surrounding
* param 0: x coordinate
* param 1: y coordinate
* param 2: color representation int
*/
var x = argument[0];
var y = argument[1];
var color = argument[2];

// I like to immediately set my parameters to var's in scripts where I know the script will be it's own contained unit that should NOT have an impact on the object that it gets ran in.

for(var x_offset = -1; x_offset < 1; x_offset++){
   for(var y_offset = -1; y_offset < 1; y_offset++){
      //Double for loop will aid us in looking into all indexes around us(this will also check ourselves though which we can skip
      if(!(x_offset == 0 && y_offset == 0)){//if both offset values are not zero
         x_index_checking = x + x_offset;
         y_index_checking = y + y_offset;

         //Now you know the indexes of one of the surrounding slots, with that you can say:  global.IndexFilled[x_index_checking][y_index_checking]
         //To find the value that slot is holding.
      }
   }
}
keep in mind that this is a script that you will call from an object. So youÄşl say in the object something like:
Code:
if(collision){
   scr_set_location_of_bubble();//This would also be a script that edits the bubble's location
   scr_Check_Surrounding(x,y,color);
}
If you don understand what I am talking check this
 
M

Matt93

Guest
I'll extend what I wrote down a little bit. That should make it more clear. I actually intended to write what I am going to add now originally but mid writing forgot to :p

Code:
/*
* script name: scr_Check_Surrounding
* param 0: x coordinate
* param 1: y coordinate
* param 2: color representation int
*/
var x = argument[0];
var y = argument[1];
var color = argument[2];

// I like to immediately set my parameters to var's in scripts where I know the script will be it's own contained unit that should NOT have an impact on the object that it gets ran in.

for(var x_offset = -1; x_offset < 1; x_offset++){
   for(var y_offset = -1; y_offset < 1; y_offset++){
      //Double for loop will aid us in looking into all indexes around us(this will also check ourselves though which we can skip
      if(!(x_offset == 0 && y_offset == 0)){//if both offset values are not zero
         x_index_checking = x + x_offset;
         y_index_checking = y + y_offset;

         //Now you know the indexes of one of the surrounding slots, with that you can say:  global.IndexFilled[x_index_checking][y_index_checking]
         //To find the value that slot is holding.
      }
   }
}
keep in mind that this is a script that you will call from an object. So youÄşl say in the object something like:
Code:
if(collision){
   scr_set_location_of_bubble();//This would also be a script that edits the bubble's location
   scr_Check_Surrounding(x,y,color);
}
If you don understand what I am talking check this
Thank you! You're so helpful. Why have you used x_offset and y_offset?

Edit: Oh, is that so it checks one cell away?

Edit 2: and can I just put global.IndexFilled[x_index_checking, y_index_checking] within the loop? Underneath the lines just above? And what do I want to do with that information?

I have done this, although I'm not sure whether it's right?

Code:
for(var x_offset = -1; x_offset < 1; x_offset++){
   for(var y_offset = -1; y_offset < 1; y_offset++){
      //Double for loop will aid us in looking into all indexes around us(this will also check ourselves though which we can skip
      if(!(x_offset == 0 && y_offset == 0)){//if both offset values are not zero
         x_index_checking = X + x_offset;
         y_index_checking = Y + y_offset;
         if (global.IndexFilled[x_index_checking, y_index_checking]) = 1
         {
            if (!checked) checked = true; 
         }
   }
}
}
 
Last edited by a moderator:
T

TDSrock

Guest
Thank you! You're so helpful. Why have you used x_offset and y_offset?
The offsets are used to take grab a 3x3 of indexes. as we will need to check:
1 above 1 left, 1 above, 1 above 1 right, 1 left, 1 right, 1 down 1 left, 1 down, 1 down 1 right

to visualize

each "o" represents an array index:
Code:
oooooooooo
oooooooooo
oooooooooo
oooooooooo
oooooooooo
oooooooooo
Now say I want to check the indexes surrounding the capital in this one:

Code:
oooooooooo
oooooooooo
oooooooooo
oooooOoooo
oooooooooo
oooooooooo
So that means we need to figure out the one's denoted with an x
Code:
oooooooooo
oooooooooo
ooooxxxooo
ooooxOxooo
ooooxxxooo
oooooooooo
The two offset loops make it so the script hits the one's denoted as an x is in the above visual example. As O would be a known location, the parameters to the function. (x and y in the script I wrote down) x - 1 and y - 1 is the top left x denoted in the visual example.

Edit: Oh, is that so it checks one cell away?
You can only check one cell at a time, the for loop runs through it 9 times and it skips the instance where x_offset and y_offset are both 0 as is the original


Edit 2: and can I just put global.IndexFilled[x_index_checking, y_index_checking] within the loop? Underneath the lines just above? And would I put = checked after it?
Yes that code NEEDS to be inside the loop, I would place it after the comment in the code which is this line: //To find the value that slot is holding.

Not there just yet.
First store the object in the array slot in a varaible so you can call it easier.
something like inst
check if that the inst has already been checked, if so you can move on. so
Code:
if(inst.checked){

}
Now that you are checking the inst, tell the inst that is has been checked by saying inst.checked = true,
from there all you need to do is check if the color of inst is the same as the color passed. if that is true you'll do this line:
Code:
scr_Check_Surrounding(x_index_checking,y_index_checking, color);
to start the recursion.
 
M

Matt93

Guest
The offsets are used to take grab a 3x3 of indexes. as we will need to check:
1 above 1 left, 1 above, 1 above 1 right, 1 left, 1 right, 1 down 1 left, 1 down, 1 down 1 right

to visualize

each "o" represents an array index:
Code:
oooooooooo
oooooooooo
oooooooooo
oooooooooo
oooooooooo
oooooooooo
Now say I want to check the indexes surrounding the capital in this one:

Code:
oooooooooo
oooooooooo
oooooooooo
oooooOoooo
oooooooooo
oooooooooo
So that means we need to figure out the one's denoted with an x
Code:
oooooooooo
oooooooooo
ooooxxxooo
ooooxOxooo
ooooxxxooo
oooooooooo
The two offset loops make it so the script hits the one's denoted as an x is in the above visual example. As O would be a known location, the parameters to the function. (x and y in the script I wrote down) x - 1 and y - 1 is the top left x denoted in the visual example.


You can only check one cell at a time, the for loop runs through it 9 times and it skips the instance where x_offset and y_offset are both 0 as is the original



Yes that code NEEDS to be inside the loop, I would place it after the comment in the code which is this line: //To find the value that slot is holding.

Not there just yet.
First store the object in the array slot in a varaible so you can call it easier.
something like inst
check if that the inst has already been checked, if so you can move on. so
Code:
if(inst.checked){

}
Now that you are checking the inst, tell the inst that is has been checked by saying inst.checked = true,
from there all you need to do is check if the color of inst is the same as the color passed. if that is true you'll do this line:
Code:
scr_Check_Surrounding(x_index_checking,y_index_checking, color);
to start the recursion.
Okay I have this code now:

Code:
for(var x_offset = -1; x_offset < 7; x_offset++){
   for(var y_offset = -1; y_offset < 7; y_offset++){
      //Double for loop will aid us in looking into all indexes around us(this will also check ourselves though which we can skip
      if(!(x_offset == 0 && y_offset == 0)){//if both offset values are not zero
         x_index_checking = X + x_offset;
         y_index_checking = Y + y_offset;
         inst = (global.IndexFilled[x_index_checking, y_index_checking])
         if (inst.checked)
         {
       
         }
         else (inst.checked) = true;
         scr_check_surrounding(x_index_checking,y_index_checking);

   }
}
}
I haven't added in my colour parameter yet, since I only have one type of bubble at the moment. Is this right? Then do I also call the script in the bubble collision event? Thank you for the detailed visualisation, that really helped. Also, if I want the for loop to loop 9 times, should the code be

for(var x_offset = -1; x_offset < 7; x_offset++){
for(var y_offset = -1; y_offset < 7; y_offset++){

?
 
T

TDSrock

Guest
No as is it will already in total loop 9 times.

The first one loops 3 times.
The second one inside the first loop loops 3 times.
The result is 3*3. 3*3 = 9

Your if statements are off currently.(assuming global.IndexFilled is a array filled with instances. as the array could also be filled with -1(empty) we should check for that first ;)
 
M

Matt93

Guest
No as is it will already in total loop 9 times.

The first one loops 3 times.
The second one inside the first loop loops 3 times.
The result is 3*3. 3*3 = 9

Your if statements are off currently.(assuming global.IndexFilled is a array filled with instances. as the array could also be filled with -1(empty) we should check for that first ;)
How about now? Thank you so much for your patience with my coding!
Code:
if (inst = -1) || (inst.checked)
         {
           
         }
         else if (inst = 1) && (inst.checked = false) inst.checked = true;
         scr_check_surrounding(x_index_checking,y_index_checking);
 
T

TDSrock

Guest
Close real close.
You just forgot our good friend curly brackets. There is also a way to make that first line a bit cleaner.

Code:
if (!(inst = -1 && inst.checked)) // if not ( inst = -1 and inst.checked)
         {
          inst.checked = true;
         scr_check_surrounding(x_index_checking,y_index_checking);
         }
Now we don need that else :)
 
M

Matt93

Guest
Close real close.
You just forgot our good friend curly brackets. There is also a way to make that first line a bit cleaner.

Code:
if (!(inst = -1 && inst.checked)) // if not ( inst = -1 and inst.checked)
         {
          inst.checked = true;
         scr_check_surrounding(x_index_checking,y_index_checking);
         }
Now we don need that else :)
Excellent, thank you! Now I'm calling the script in the bubble's step event:
Code:
if (distance_to_point(global.target_x, global.target_y) < 5)
{
    speed = 0;
    x = global.X_LocationOfIndex [(x-80) div 32, 2]
    y = global.Y_LocationOfIndex [2, (y - 40) div 32 ]
    //global.X_LocationOfIndex [(x-80) div 32, 2] = -1;
    //global.Y_LocationOfIndex [2, (y - 40) div 32 ] = 1;
    global.X_IndexFilled[(x-80) div 32, 2] = 1;
    global.Y_IndexFilled[2, (y - 40) div 32]  = 1;
    scr_check_surrounding(x,y); 
   
   
}
Is that the right way of doing it? And then after that has been called, how can I use instance_destroy in tandem with that information? I feel like I'm nearly there now!
 
T

TDSrock

Guest
Say your bubble lands at [3,9] then you'll call scr_check_surrounding with 3,9

In the scr_check_surrounding for each that we find to be the same color as the one shot we need to set a Boolean to true. (sameAs I think I called it sometime ago) So put that just before the recursion start.
Then we'll loop through the entire grid one more time (the width and height for loops)
Look into every object, if the object has his sameAs flag set to true; run instance_destroy(), if it does not set checked back to false.
 
M

Matt93

Guest
Say your bubble lands at [3,9] then you'll call scr_check_surrounding with 3,9

In the scr_check_surrounding for each that we find to be the same color as the one shot we need to set a Boolean to true. (sameAs I think I called it sometime ago) So put that just before the recursion start.
Then we'll loop through the entire grid one more time (the width and height for loops)
Look into every object, if the object has his sameAs flag set to true; run instance_destroy(), if it does not set checked back to false.
Okay so I've added a line into scr_check_surrounding:
Code:
         if (!(inst = -1 && inst.checked))
         {
         (inst.checked) = true;
         if (inst.colour = colour) inst.same_as = true;
         scr_check_surrounding(x_index_checking,y_index_checking);
        }

   }
}
}
Is that right? How would I set up the colour var in the bubble objects - with an array?

And this code in obj_bubble is throwing an error:
Code:
if (distance_to_point(global.target_x, global.target_y) < 5)
{
    speed = 0;
    x = global.X_LocationOfIndex [(x-80) div 32, 2]
    y = global.Y_LocationOfIndex [2, (y - 40) div 32 ]
    global.X_IndexFilled[(x-80) div 32, 2] = 1;
    global.Y_IndexFilled[2, (y - 40) div 32]  = 1;
    scr_check_surrounding(x,y);
but I thought logically, I want to run the script from the x and y coordinates of the bubble. I'm not sure what I'm missing here.

Edit: I think to set the colour, I would just have each different colour of ball parented to a ball object. Then each individual object would have a colour variable. Eg colour = "blue", colour = "red" etc. Then I think it would cross-reference in the script. Or maybe I would have to use numbers, as I feel like using strings is the wrong thing to do. This is why I was asking about the array. Would it have to be colour[0] = -1, colour[1] = 1 etc?

Edit 2: I've just realised I would have to get the INDEX of where the bubble lands. Rather than the actual x and y coordinates. So, scr_check_surrounding((x-80) div 32, (y-40) div 32,0) I think.

I have also added code into the script to loop back through the width and height. It's throwing an error though, and I also feel like the way I'm trying to do it is wrong. I'm avoiding this by using a conditional if (instance_exists). I've done this further up with var inst as well, as that code has seemed to occasionally throw an error. I thought I could assign the coordinate's instance to a variable, then interact with that variable (to destroy the instance):

Code:
if (!(inst = -1 && inst.checked)) //if slot is full and unchecked
         {
         if (instance_exists(inst)){
         inst.checked = true;
         if (inst.colour = colour) inst.same_as = true; //
         scr_check_surrounding(x_index_checking,y_index_checking,colour);
         for(i=0; i<obj_control.width;i++){//width represents the number of blocks in the width
        for(j=0; j<20;j++){
      var inst_2 = global.X_LocationOfIndex[i,j]
      if (instance_exists(inst_2))
      {
        if!(inst_2.same_as) instance_destroy();
      }
      else checked = false;
 
Last edited by a moderator:
T

TDSrock

Guest
Okay so I've added a line into scr_check_surrounding:
Edit: I think to set the colour, I would just have each different colour of ball parented to a ball object. Then each individual object would have a colour variable. Eg colour = "blue", colour = "red" etc. Then I think it would cross-reference in the script. Or maybe I would have to use numbers, as I feel like using strings is the wrong thing to do. This is why I was asking about the array. Would it have to be colour[0] = -1, colour[1] = 1 etc?
No that is unnecisary. All we need to do is store the objectĹ› themselves in the array.
Thay way when we say:
Code:
inst = obj_grid[5][4];//changed the name here
this would let us follow it up by doing

Code:
if(inst != -1){
   switch(inst.color){
      case "blue" :
         //stuff to do if blue bubble is found
      break;
      default:
         //none of the above cases were found
   }
}
But becuase we will be calling the function with a color the line:

Code:
         if (inst.colour = colour) inst.same_as = true;
Will be enough to deal with the color ;)

Edit 2: I've just realised I would have to get the INDEX of where the bubble lands. Rather than the actual x and y coordinates. So, scr_check_surrounding((x-80) div 32, (y-40) div 32,0) I think.
Jup jup. When we wrote the function we decided to expect indexes, this makes it easier when doing the recursion calls, else we have to go from index values to room values constantly.

I have also added code into the script to loop back through the width and height. It's throwing an error though, and I also feel like the way I'm trying to do it is wrong. I'm avoiding this by using a conditional if (instance_exists). I've done this further up with var inst as well, as that code has seemed to occasionally throw an error. I thought I could assign the coordinate's instance to a variable, then interact with that variable (to destroy the instance):

Code:
if (!(inst = -1 && inst.checked)) //if slot is full and unchecked
         {
         if (instance_exists(inst)){
         inst.checked = true;
         if (inst.colour = colour) inst.same_as = true; //
         scr_check_surrounding(x_index_checking,y_index_checking,colour);
         for(i=0; i<obj_control.width;i++){//width represents the number of blocks in the width
        for(j=0; j<20;j++){
      var inst_2 = global.X_LocationOfIndex[i,j]
      if (instance_exists(inst_2))
      {
        if!(inst_2.same_as) instance_destroy();
      }
      else checked = false;
What is the exact error. First guess is a out of bounds error (array) or something like that.

It is an error the script we wrote already will run into as one of it's bugs, but it's relatively easy to sort out.
 
M

Matt93

Guest
But becuase we will be calling the function with a color the line:

Code:
if (inst.colour = colour) inst.same_as = true;
Will be enough to deal with the color ;)
Ah, great. So does each different bubble object just need to have a colour variable which is set to, say, "blue" for the blue one, "red" for red etc? And then this can be read from that line of code in the script? So in the bubble collision, do I just have to run the script with a different colour argument, depending on which bubble object I'm calling it from? So
Code:
scr_check_surrounding((x-80) div 32, (y-40) div 32, "blue")
if I'm calling it from the blue bubble object and so on?

What is the exact error. First guess is a out of bounds error (array) or something like that.

It is an error the script we wrote already will run into as one of it's bugs, but it's relatively easy to sort out.
I think I was getting an out of bounds error before I added these lines in. But this is actually an instance not found error - which is why putting in if instance_exists(inst_2) got rid of it. The error message is:

Unable to find any instance for object index '80' name '<undefined>'
at gml_Script_scr_check_surrounding (line 31) - if!(inst_2.same_as) instance_destroy();
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Script_scr_check_surrounding (line 31)
called from - gml_Object_obj_bubble_fixed_CreateEvent_1 (line 5) - scr_check_surrounding(2,10,0);
This is why I thought I must be misusing the for loop. Is referring to global.X_LocationOfIndex[i,j] the right way of doing it? That is also only the x coordinates, as I don't think I can assign inst_2 to both global.XLocationOfIndex and global.YLocationOfIndex. Correct me if I'm wrong though ;)

I'm also getting this error with my inst code:
Unable to find any instance for object index '1'
at gml_Script_scr_check_surrounding (line 23) - inst.checked = true;
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Script_scr_check_surrounding (line 23)
called from - gml_Script_scr_check_surrounding (line 27) - scr_check_surrounding(x_index_checking,y_index_checking,colour);
called from - gml_Object_obj_bubble_StepNormalEvent_1 (line 29) - with (bubble) scr_check_surrounding((x-80) div 32,(y-40) div 32,"blue");
Is inst = (global.IndexFilled[x_index_checking, y_index_checking]) the correct way of assigning the grid slot to a variable? I think this line is what's causing the error.

Thank you!

Edit: I don't think that inst code will be getting the actual instance in the slot. That object index '1' in the error message must be referring to how I set the value of the slot to 1. Hmmm, how do I actually retrieve the instance which is in that slot once I know it's full? I imagine I need to get the id?
 
Last edited by a moderator:
T

TDSrock

Guest
Ah, great. So does each different bubble object just need to have a colour variable which is set to, say, "blue" for the blue one, "red" for red etc? And then this can be read from that line of code in the script? So in the bubble collision, do I just have to run the script with a different colour argument, depending on which bubble object I'm calling it from? So
Code:
scr_check_surrounding((x-80) div 32, (y-40) div 32, "blue")
if I'm calling it from the blue bubble object and so on?
Yes but it could be even simpler.
If you tell each bubble on spawn which color it by doing something like this in the create event:
Code:
color = choose("red", "blue","green");
Then you can call it the first time by saying:

Code:
scr_check_surrounding((x-80) div 32, (y-40) div 32, color)

I think I was getting an out of bounds error before I added these lines in. But this is actually an instance not found error - which is why putting in if instance_exists(inst_2) got rid of it. The error message is:



This is why I thought I must be misusing the for loop. Is referring to global.X_LocationOfIndex[i,j] the right way of doing it? That is also only the x coordinates, as I don't think I can assign inst_2 to both global.XLocationOfIndex and global.YLocationOfIndex. Correct me if I'm wrong though ;)
Well for that we need to know how the array we are trying to pull our instances out of is defined.
What I assume is that empty slots would be equal to -1.
if it's anything else it would be an instance.

So lets double check that first ;)
How are you initializing the array currently, and how are you adding your instances to the array.?

I'm also getting this error with my inst code:


Is inst = (global.IndexFilled[x_index_checking, y_index_checking]) the correct way of assigning the grid slot to a variable? I think this line is what's causing the error.

Thank you!
In that line you are reading out the index and storing it in an easier to remember variable, namely inst.

so what we should be reading out here is the array/grid that has all the objects or the -1's in them. then we check if inst != -1. if it is we can safely assume it's an instance.


Lets just drop in all relevant code so we can do a general read through everything to see whats up where.
 
M

Matt93

Guest
Well for that we need to know how the array we are trying to pull our instances out of is defined.
What I assume is that empty slots would be equal to -1.
if it's anything else it would be an instance.

So lets double check that first ;)
How are you initializing the array currently, and how are you adding your instances to the array.?
Okay, let's go! The array global.IndexFilled is initialised in the create event of my control object. -1 represents an empty slot. I had to use 20, rather than my actual height variable, because I fill a portion of the grid with initial instances (as you'll see in the code section below this one), but there needs to be more height in the grid than is filled by these.
Code:
for(i=0; i<width;i++){//width represents the number of blocks in the width
   for(j=0; j<20;j++){
        global.IndexFilled[i,j] = -1; //empty slot     
   }
}
Then also in the create event of my control object, I create some instances of obj_bubble_fixed (bubble objects which do not move). I also think there might be a problem in my actual gameplay setup, as at the moment, I have two separate bubble objs, one which follows where you shoot, and one which sticks in place. It would probably be far easier to use a var in a single object. But we'll get on to that ;) Okay, so my code for creating these fixed objects, which are there at the beginning of the game:

Code:
for(i=0; i<width;i++){//width represents the number of blocks in the width
   for(j=0; j<height;j++){
      bubble_fixed = instance_create(global.X_LocationOfIndex[i,j],  global.Y_LocationOfIndex[i,j], obj_bubble_fixed)
      global.IndexFilled [i,j] = 1; //fills slot
   }
}
This game is touch screen, so tapping then releasing creates a target object, which the moving bubble, when it is shot, then moves towards. This is in the moving obj_bubble's step:
Code:
if (move)
{
    move_towards_point(global.target_x, global.target_y, 10)
   
}
Then, when the moving bubble is within a certain range of the target, we stop it moving, snap it to the grid, and fill the appropriate index. Again, I think the whole within target range logic could be improved, but here's my code:

Code:
if (distance_to_point(global.target_x, global.target_y) < 5)
{
    speed = 0;
    x = global.X_LocationOfIndex [(x-80) div 32, 2] //snap
    y = global.Y_LocationOfIndex [2, (y - 40) div 32 ] //snap
    global.IndexFilled[(x-80) div 32, (y-40) div 32] = 1 //fill index
After this, the moving bubble object is destroyed, and an instance of the 'stuck' bubble object is created in the same place:

Code:
instance_destroy();
    bubble = instance_create(x,y,obj_bubble_fixed);
}
And just for good measure, I'm going to put the entire scr_check_surrounding code here:

Code:
/*
* script name: scr_Check_Surrounding
* param 0: x coordinate
* param 1: y coordinate
* param 2: color representation int
*/
var X = argument[0];
var Y = argument[1];
var colour = argument[2];

// I like to immediately set my parameters to var's in scripts where I know the script will be it's own contained unit that should NOT have an impact on the object that it gets ran in.

for(var x_offset = -1; x_offset < 1; x_offset++){
   for(var y_offset = -1; y_offset < 1; y_offset++){
      //Double for loop will aid us in looking into all indexes around us(this will also check ourselves though which we can skip
      if(!(x_offset == 0 && y_offset == 0))
      {//if both offset values are not zero
         x_index_checking = X + x_offset;
         y_index_checking = Y + y_offset;
         inst = (global.IndexFilled[x_index_checking, y_index_checking])
         if (!(inst = -1 && inst.checked)) //if slot is full and unchecked
         {       
            inst.checked = true;
            if (inst.colour = colour)
            {
                inst.same_as = true;
                scr_check_surrounding(x_index_checking,y_index_checking,colour);
                for(i=0; i<obj_control.width;i++){//width represents the number of blocks in the width
                for(j=0; j<20;j++){
                var inst_2 = global.X_LocationOfIndex[i,j]
                if(inst_2.same_as) instance_destroy(); //&& (inst_2_y.same_as) instance_destroy();
            }
Thank you so much! I'm really enjoying working through this with you :)
 
T

TDSrock

Guest
Okay first off scr_check_surrounding has is wrong currently.

The double for loop you are running inside it shouldn't be there!

In the object where we start the call we'll do:
Code:
scr_check_surrounding(x,y,color);
scr_remove_same();//this will need to parameters as we'll be looking through everything
We'll be needing a value though that tracks the same_as counts.
So there we could use: global.same_as_count
In the room creation code we'll need to declare it like this:
Code:
global.same_as_count = 0;
Now in our scr_check_surrounding we need to add, in the right place, global.same_as_count++
which means the same as
Code:
//The following lines are all effectively exactly the same!
global.same_as_count++;
global.same_as_count += 1;
global.same_as_count = global.same_as_count + 1;
Now scr_remove_same should look something like this:
Code:
/*
* script name: scr_remove_same
*/

//Note this one will be in human speach, I'll leave it to you to actually implement it!


Double for loop to loop through entire array{
   inst = the instance in the index;
   if(inst != -1){
      with(inst){
         //code ran here is actualy ran inside the instace that we have
         if same_as flag is true and if global.same_as_count is larger then minimum same as value, destroy self  //I assume you won't want things to always delete, Whatever constant used here will be the threshold
         else /*the same_as flag is true, but the count isn't high enough to allow objects being removed, so we need to reset it's same_as flag*/ same_as = false;
      }
   }
}

//Done with the double for loop everything should've be deleted
reset global.same_as count

On the second point I'll tackle the bubble moving and placing it in the index.

So you do:
Code:
if (distance_to_point(global.target_x, global.target_y) < 5)
{
    speed = 0;
    x = global.X_LocationOfIndex [(x-80) div 32, 2] //snap
    y = global.Y_LocationOfIndex [2, (y - 40) div 32 ] //snap
    global.IndexFilled[(x-80) div 32, (y-40) div 32] = 1 //fill index
}
Which is really close! Just a little bit off. The main thing I would change is filling the index. Your now just placing the number 1. However our other code that references that index is expecting an instance. The number one MIGHT refer to an instance but probably won't.
Instead change the 1 to the keyword "this". Pretty sure that works.
It explains one of the errors you had, you were checking if inst actually was an instance, but it never would be. Why? Well the array was filled with 1 and -1, neither represent an instance.

The moving bubble destroy and fixed bubble create is something i would just not do.
First problem, it wrecks our code. Our code is expecting an instance. However by deleting the instance and placing another one the instance we put into the grid will bea different one.
If you still want to do it it's possible you'll just need to change things a little bit

Code:
instance_destroy();
    bubble = instance_create(x,y,obj_bubble_fixed);
}
Also as a side note, I would advise creating the new instance before deleting the one you are running the code in.
So that this would become this:

Code:
    bubble = instance_create(x,y,obj_bubble_fixed);
    x = global.X_LocationOfIndex [(x-80) div 32, 2] //snap
    y = global.Y_LocationOfIndex [2, (y - 40) div 32 ] //snap
    global.IndexFilled[(x-80) div 32, (y-40) div 32] = bubble //fill index
    instance_destroy();
Now I am going to go into the initialization of the grid.

So first here:
Code:
for(i=0; i<width;i++){//width represents the number of blocks in the width
   for(j=0; j<20;j++){
        global.IndexFilled[i,j] = -1; //empty slot     
   }
}
I would instead of that constant 20 just do the whole height. It doesn't matter that much to save the rest for later. And it leaves us with the knowlege that it's garaunteed to be -1 or an instance.

The other code block this one:
Code:
for(i=0; i<width;i++){//width represents the number of blocks in the width
   for(j=0; j<height;j++){
      bubble_fixed = instance_create(global.X_LocationOfIndex[i,j],  global.Y_LocationOfIndex[i,j], obj_bubble_fixed)
      global.IndexFilled [i,j] = 1; //fills slot
   }
}
Well we get the same problem as adressed before. Filling the index with 1, an integer instead of an instance. Luckly easily fixed by doing this instead:

Code:
for(i=0; i<width;i++){//width represents the number of blocks in the width
   for(j=0; j<height;j++){
      bubble_fixed = instance_create(global.X_LocationOfIndex[i,j],  global.Y_LocationOfIndex[i,j], obj_bubble_fixed)
      global.IndexFilled [i,j] = bubble_fixed; //fills slot
   }
}
I went at this post in a somewhat odd manner(the order I hit everything in)
So I hope you don't get lost due to that. I also hope I hit all the parts that had issues with them, the movement code looks find to me.
 
T

TDSrock

Guest
BTW I'd be happy to take this into Skype or Discord over the weekend so we can talk and the feedback is more instantaneous.
I'll link you to the GMC discord
 
M

Matt93

Guest
Thank you SO much for all your help. You've taken so much time to help me, and I'm so grateful! Right, I've applied those code changes, which I'm just going to put here, to check they're right:

Firstly, scr_check_surrounding:
Code:
for(var x_offset = -1; x_offset < 1; x_offset++){
   for(var y_offset = -1; y_offset < 1; y_offset++){
      //Double for loop will aid us in looking into all indexes around us(this will also check ourselves though which we can skip
      if(!(x_offset == 0 && y_offset == 0))
      {//if both offset values are not zero
         x_index_checking = X + x_offset;
         y_index_checking = Y + y_offset;
         inst = (global.IndexFilled[x_index_checking, y_index_checking])
         if (!(inst = -1 && inst.checked)) //if slot is full and unchecked
         {       
            inst.checked = true;
            if (inst.colour = colour)
            {
                inst.same_as = true;
                global.same_as_count ++;
                scr_check_surrounding(x_index_checking,y_index_checking,colour);
            }         
         }

        }

    }
}
Scr_remove_same:
Code:
for(i=0; i<obj_control.width;i++){//width represents the number of blocks in the width
for(j=0; j<obj_control.height;j++){
inst = global.index_filled[i, j] //this line may not be right?
if (inst != -1)
{
    with (inst)
    {
        if (same_as == 1) && (global.same_as > 2) instance_destroy();
        else same_as = false;
    }
}

    }
}

global.same_as_count = 0;
The main line I was unsure about was the one where you define inst.


The bubble moving and placing it in the index (Bubble step event):
Code:
if (distance_to_point(global.target_x, global.target_y) < 5)
{
    speed = 0;
    x = global.X_LocationOfIndex [(x-80) div 32, 2]
    y = global.Y_LocationOfIndex [2, (y - 40) div 32 ]
    global.IndexFilled[(x-80) div 32, (y-40) div 32] = self; //equivalent of "this" which you suggested?
    bubble = instance_create(x,y,obj_bubble_fixed); //this line needs to be below x= and y= so the obj snaps correctly to the grid
    instance_destroy();
    obj_shooter.waiting = false;
}
The main change I made from your suggestion was putting the creation of obj_bubble fixed below the x and y = global.LocationOfIndex lines. As the new object wasn't snapping to the grid correctly otherwise. I changed the 1 to self, rather than "this", for the IndexFilled line. I don't think the keyword this exists in GML, so I thought self would probably be the equivalent?

For the initialisation of the grid, in obj_control, I also changed that constant 20 to the height, as you suggested:
Code:
for(i=0; i<width;i++){//width represents the number of blocks in the width
   for(j=0; j<height;j++){
        global.IndexFilled[i,j] = -1; //empty slot     
   }
}
And I also changed the 1 to bubble_fixed in the initialisation of the fixed bubble instances:
Code:
for(i=0; i<width;i++){//width represents the number of blocks in the width
   for(j=0; j<height;j++){
      bubble_fixed = instance_create(global.X_LocationOfIndex[i,j],  global.Y_LocationOfIndex[i,j], obj_bubble_fixed)
      global.IndexFilled [i,j] = bubble_fixed; //fills slot
   }
}
I am running scr_check_surrounding from the bubble step event, where the bubble is also moved, changed to a fixed object, and snapped to the grid:
Code:
if (distance_to_point(global.target_x, global.target_y) < 5)
{
    speed = 0;
    x = global.X_LocationOfIndex [(x-80) div 32, 2]
    y = global.Y_LocationOfIndex [2, (y - 40) div 32 ]
    global.IndexFilled[(x-80) div 32, (y-40) div 32] = self;
    bubble = instance_create(x,y,obj_bubble_fixed);
    scr_check_surrounding((x-80) div 32, (y-40) div 32, "blue")
    instance_destroy();
    obj_shooter.waiting = false;
}
I'm not sure if this is the right place to call it from, but I wasn't sure where else I would do this?

When I run the game, and fire a bubble, I get this error:
Code:
FATAL ERROR in
action number 1
of  Step Event0
for object obj_bubble:

Push :: Execution Error - Variable Index [5,8] out of range [15,8] - -5.IndexFilled(100000,160008)
at gml_Script_scr_check_surrounding (line 20) -          inst = (global.IndexFilled[x_index_checking, y_index_checking])
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Script_scr_check_surrounding (line 20)
called from - gml_Object_obj_bubble_StepNormalEvent_1 (line 13) -     scr_check_surrounding((x-80) div 32, (y-40) div 32, "blue")
I have also tried running the script with constant numbers (for example, scr_check_surrounding(2,3,"blue") and got this error:
Code:
FATAL ERROR in
action number 1
of  Step Event0
for object obj_bubble:

Array index must be +'ve
at gml_Script_scr_check_surrounding (line 20) -          inst = (global.IndexFilled[x_index_checking, y_index_checking])
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Script_scr_check_surrounding (line 20)
called from - gml_Script_scr_check_surrounding (line 28) -                 scr_check_surrounding(x_index_checking,y_index_checking,colour);
called from - gml_Script_scr_check_surrounding (line 28) -                 scr_check_surrounding(x_index_checking,y_index_checking,colour);
called from - gml_Object_obj_bubble_StepNormalEvent_1 (line 13) -     scr_check_surrounding(2,3,"blue")
I can't even think why this is happening? I haven't tried calling scr_remove_same yet, as I thought we should tackle this problem first! I am going to reply to your second post after this one.
 
M

Matt93

Guest
BTW I'd be happy to take this into Skype or Discord over the weekend so we can talk and the feedback is more instantaneous.
I'll link you to the GMC discord
It would be amazing to talk over Skype or Discord. I hadn't even imagined a game which seems so simple could be so complicated! I'm determined to crack this. I'm around tomorrow (London timezone), and also this weekend. So just let me know when would work for you? In the meantime, I'm going to be chipping away at this. If you have any ideas once you've seen my post, just let me know if you want to chat (or post any thoughts on here if it's easier for you/you can't get on chat). Also, if it's easier for you to take a look at the actual .gmx file, I can link you to that. Thank you so much! Can we share Skype ids on the forums without getting our posts deleted? I'll give you mine if so. Or we can just use Discord :)
 
Last edited by a moderator:
T

TDSrock

Guest
scr_check_surrounding looks correct to me. Besides the out of range error that it can cause.
Here's why

say I have an array that is 5 by 5 grid (so the indexes are [0 to 4][0 to 4]
If we were to ask any number that is not within that we will be looking into an index that does not exist.
if scr_check_surrounding gets called with for example [0][0]
Both offset value's will be -1.

So how do fix this? if we can see that one of the offsets is -1 we need to skip the index from testing.
if x offset is larger then the width or the y offset is larger then the height we also need the skip the index from testing. Once that is in scr_check_surrounding shouldn't cause this error anymore.


scr_remove_same is almost correct, the only thing you are doing wrong is the variable you are referencing.
We've stored our values in the variable: global.IndexFilled not global.index_filled ;)
Ohh also, a thing I forgot to state before, if the bubble is getting deleted, we'll also need to update global.IndexFilled.
The index will need to become -1.

also just as a side-note checking if a Boolean is true or false makes no sense. If statements content occur if the conditional is true.
The reason we may do
Code:
if( someInteger == 4){

}
Is because someInteger == 4 will fall down to a Boolean, either that is true, or it's false.
If we already are a Boolean we can do these two things to differentiate between true and false:
Code:
if(Boolean){
//do stuff when Boolean is true
}

if(!Boolean){
//do stuff if Boolean is false
}
Now you want to use that bubble_fixed object. Thats perfectly fine but you do need to keep in mind what you are storing inside global.IndexFilled.
It should be filled with -1 and the actual in game instances. You are filling it with self (and yes self is gml's this), Then creating something else,
Then deleting self.
So the instance we just stored has been deleted.
So swap these two lines
Code:
global.IndexFilled[(x-80) div 32, (y-40) div 32] = self; //equivalent of "this" which you suggested?
    bubble = instance_create(x,y,obj_bubble_fixed); //this line needs to be below x= and y= so the obj snaps correctly to the grid
and change self to bubble.
This occurs twice I believe. ( in the code you posted).


Now on the two errors. I've elaborated on the first one.
But so you can debug these kinds of issues on your own on the future.

The line we care about first is this one:
Code:
Push :: Execution Error - Variable Index [5,8] out of range [15,8] - -5.IndexFilled(100000,160008)
So here gml is telling you that an out of range error occurred. This means again that you tried to access an part of the array that was never internalized.
Look at the above part to fix the issue

On the second one
Code:
Array index must be +'ve at gml_Script_scr_check_surrounding (line 20) -          inst = (global.IndexFilled[x_index_checking, y_index_checking])
This to me reads that array indexes must be positive. -1 or smaller shouldn't ever be called at the lowest 0.
This is happening due to two things.
Recursion calls and the double for loop thats checking the surrounding indexes.



It's perfectly fine to post Skype ID's. I just kinda hate Skype since recently, it's just been really bad performance wise, main reason I'd be willing to budge is to use the screen share feature. Otherwise might as well use discord. If not the GMC discord one that we just make to use for this.
My Skype ID is find-able on my account on the GMC and for good measure it's TDSrock.
 
M

Matt93

Guest
Thank you so much! I'm just a bit confused about this section:
scr_check_surrounding looks correct to me. Besides the out of range error that it can cause.
Here's why

say I have an array that is 5 by 5 grid (so the indexes are [0 to 4][0 to 4]
If we were to ask any number that is not within that we will be looking into an index that does not exist.
if scr_check_surrounding gets called with for example [0][0]
Both offset value's will be -1.

So how do fix this? if we can see that one of the offsets is -1 we need to skip the index from testing.
if x offset is larger then the width or the y offset is larger then the height we also need the skip the index from testing. Once that is in scr_check_surrounding shouldn't cause this error anymore.
I thought x_offset and y_offset could only be -1 or 0 in that for loop in scr_surrounding? So how could x_offset or y_offset be larger than the height? Also, if I skip the index if these are -1, won't the code just not run at all because I've already told it to skip the index if x and y_offset are 0? I think I'm misunderstanding where to put this code in. I've added you on Skype just in case anyway :) Cheers
 
T

TDSrock

Guest
x_offset and y_offset will be -1, 0, and 1 each.
However x + x_offset can be larger.

We woulden't be skipping if x_offset is -1 or larger then the width, we'd be skipping if x_offset + x is larger or negative.

My bad there writing out allot of things it's bound for me to make small mistakes :p
 
M

Matt93

Guest
x_offset and y_offset will be -1, 0, and 1 each.
However x + x_offset can be larger.

We woulden't be skipping if x_offset is -1 or larger then the width, we'd be skipping if x_offset + x is larger or negative.

My bad there writing out allot of things it's bound for me to make small mistakes :p
Ah, that makes sense! It looks like I'm still making mistakes though :( I put this line in:

Code:
if(!(x_offset == 0 && y_offset == 0)) && (!(X + x_offset < 0 && Y + y_offset < 0))
      {//if both offset values are not zero
         x_index_checking = X + x_offset;   
         y_index_checking = Y + y_offset;
I'm still getting the same out of range error. What am I doing wrong? I'm calling it from obj_bubble with this code:

Code:
if (distance_to_point(global.target_x, global.target_y) < 5)
{
    speed = 0;
    x = global.X_LocationOfIndex [(x-80) div 32, 2]
    y = global.Y_LocationOfIndex [2, (y - 40) div 32 ]
    bubble = instance_create(x,y,obj_bubble_fixed);
    global.IndexFilled[(x-80) div 32, (y-40) div 32] = bubble;
    scr_check_surrounding((x-80) div 32, (y-40) div 32, "blue")
    instance_destroy();
 
T

TDSrock

Guest
instead of doing:
Code:
if(!(x_offset == 0 && y_offset == 0)) && (!(X + x_offset < 0 && Y + y_offset < 0))
      {//if both offset values are not zero
         x_index_checking = X + x_offset;   
         y_index_checking = Y + y_offset;
You should be comparing x_index_checking with the width of the array
Code:
      if(!(x_offset == 0 && y_offset == 0)) {//if both offset values are not zero
         x_index_checking = X + x_offset;   
         y_index_checking = Y + y_offset; 
         if(x_index_checking < Width of array here || x_index_checking > 0 || y_index_checking > 0 || y_index_checking < height of array here){
            //rest of scr here
Pretty sure that would work.
 
M

Matt93

Guest
instead of doing:
Code:
if(!(x_offset == 0 && y_offset == 0)) && (!(X + x_offset < 0 && Y + y_offset < 0))
      {//if both offset values are not zero
         x_index_checking = X + x_offset;  
         y_index_checking = Y + y_offset;
You should be comparing x_index_checking with the width of the array
Code:
      if(!(x_offset == 0 && y_offset == 0)) {//if both offset values are not zero
         x_index_checking = X + x_offset;  
         y_index_checking = Y + y_offset;
         if(x_index_checking < Width of array here || x_index_checking > 0 || y_index_checking > 0 || y_index_checking < height of array here){
            //rest of scr here
Pretty sure that would work.
I've done this now:
Code:
if(!(x_offset == 0 && y_offset == 0))
      {//if both offset values are not zero
         x_index_checking = X + x_offset;   
         y_index_checking = Y + y_offset;
         if (x_index_checking < obj_control.width || x_index_checking > 0 || y_index_checking > 0 || y_index_checking > obj_control.height)
         inst = (global.IndexFilled[x_index_checking, y_index_checking])
         if (!(inst = -1 && inst.checked)) //if slot is full and unchecked
         {       
            inst.checked = true;
            if (inst.colour = colour)
            {
                inst.same_as = true;
                global.same_as_count ++;
                scr_check_surrounding(x_index_checking,y_index_checking,colour);
but I'm still getting an out of range error?
 
T

TDSrock

Guest
before the if statements set say inst = -1;
Also might need to split up the following line into two if statements(I don't think it's an issue though):
Code:
         if (!(inst = -1 && inst.checked)) //if slot is full and unchecked
If there is another out of range error post the complete error message again and I might see whats wrong.
 
Last edited by a moderator:
T

TDSrock

Guest
How is forgetting your De Morgan's Laws not an issue?
Code:
if (!(inst == -1 || inst.checked)) //if slot is full and unchecked
As far as I'm concerned that line is doing exactly what we expect.

If you're implying that that line is one of the potential issues, instead of just blatantly referencing Morgan's laws why not elaborate on why you believe the line to not be doing what we want it too?
 
M

Matt93

Guest
before the if statements set say inst = -1;
Also might need to split up the following line into two if statements(I don't think it's an issue though):
Code:
         if (!(inst = -1 && inst.checked)) //if slot is full and unchecked
If there is another out of range error post the complete error message again and I might see whats wrong.
Okay, this is now my code:
Code:
if(!(x_offset == 0 && y_offset == 0))
      {//if both offset values are not zero
         x_index_checking = X + x_offset;   
         y_index_checking = Y + y_offset;
         inst = -1;
         if (x_index_checking < obj_control.width || x_index_checking > 0 || y_index_checking > 0 || y_index_checking > obj_control.height)
         inst = (global.IndexFilled[x_index_checking, y_index_checking])
         if (!(inst = -1))
         {
         if (inst.checked)//if slot is full and unchecked
         {       
            inst.checked = true;
            if (inst.colour = colour)
            {
                inst.same_as = true;
                global.same_as_count ++;
                scr_check_surrounding(x_index_checking,y_index_checking,colour);
            }
I'm getting this error:
Code:
FATAL ERROR in
action number 1
of  Step Event0
for object obj_bubble:

Push :: Execution Error - Variable Index [2,11] out of range [15,8] - -5.Y_LocationOfIndex(100007,64011)
at gml_Object_obj_bubble_StepNormalEvent_1 (line 10) -     y = global.Y_LocationOfIndex [2, (y - 40) div 32 ]
Thank you!
 
T

TDSrock

Guest
The array that is getting an out off range error is this one:

Code:
global.Y_LocationOfIndex
So we'll need to know how it is built up.
 
Top