Can this array check be done easier?!

Hey there, I am fairly novice to GMS2. Now, I've got a function Check_Tile(current_x, current_y, radius, tilecheck).

It checks my map array for a certain tile number (tilecheck). The array it checks is global.mapArray, I can state how far to check, in my case I checking if a tile with the ID 43 is 5 tiles away. The function works as intended, but it is a mess and I know there must be a way for things to be done simpler. I just can't get my head around a simpler way. Please could anyone give me some advice? I would be very grateful for any help.

GML:
function Check_Tile(tileX, tileY, radius, tilecheck){
var tile;
var checktileY = tileY - radius;
var checktileX = tileX - radius;
var newtilex = 0;
var newtiley = 0;
var xradius = radius;
var yradius = radius;

if(checktileY < 0) {
    yradius = radius - tileY;
}

if(checktileX < 0) {
    xradius = radius - tileX;
}

show_debug_message("check tile " + string(radius) + " tiles away");

            // up
            for(var i = 0; i < yradius; i++) {
                tile = global.mapArray[@ tileY-i];

                if(tile[@ tileX] == tilecheck) {
                    show_debug_message("Above " + string(i) + ": TRUE" );
                    return true;
                    exit;
                } else {
                        show_debug_message("Above " + string(i) + ": false" );
                }
            }
         
            // down
            for(var i = 0; i < yradius; i++) {
                tile = global.mapArray[@ tileY+i];

                if(tile[@ tileX] == tilecheck) {
                    show_debug_message("Down " + string(i) + ": TRUE" );
                    return true;
                    exit;
                } else {
                    show_debug_message("Down " + string(i) + ": false" );
                }
            }
         
            //left
            for(var i = 0; i < xradius; i++) {
                tile = global.mapArray[@ tileY];
                newtilex = tileX - i;
             
                if(tile[@newtilex] == tilecheck) {
                    return true;
                    show_debug_message("Left " + string(i) + ": TRUE" );
                    exit;
                } else {
                    show_debug_message("Left " + string(i) + ": false" );
                }
             
            }
         
            //right
            for(var i = 0; i < xradius; i++) {
                tile = global.mapArray[@ tileY];
                newtilex = tileX + i;
             
                if(tile[@newtilex] == tilecheck) {
                    return true;
                    show_debug_message("Right " + string(i) + ": TRUE" );
                    exit;
                } else {
                    show_debug_message("Right " + string(i) + ": false" );
                }
             
            }
         
            // SE
            for(var i = 0; i < xradius; i++) {
                for(var ii = 0; ii < yradius; ii++) {
                    newtilex = tileX + i;
                    newtiley = tileY + ii;
                    tile = global.mapArray[@newtiley];
                 
                    if(tile[@newtilex] == tilecheck) {
                        return true;
                        show_debug_message("SE " + string(i) + ": TRUE" );
                        exit;
                    } else {
                        show_debug_message("SE " + string(i) + ": false" );
                    }
                 
                }
            }
         
            // SW
            for(var i = 0; i < xradius; i++) {
                for(var ii = 0; ii < yradius; ii++) {
                    newtilex = tileX - i;
                    newtiley = tileY + ii;
                    tile = global.mapArray[@newtiley];
                 
                    if(tile[@newtilex] == tilecheck) {
                        return true;
                        show_debug_message("SW " + string(i) + ": TRUE" );
                        exit;
                    } else {
                        show_debug_message("SW " + string(i) + ": false" );
                    }
                 
                }
            }

            // NE 
            for(var i = 0; i < xradius; i++) {
                for(var ii = 0; ii < yradius; ii++) {
                    newtilex = tileX + i; 
                    newtiley = tileY - ii;
                    
                    tile = global.mapArray[@newtiley];
                    
                    if(tile[@newtilex] == tilecheck) {
                        return true;
                        show_debug_message("NE " + string(i) + ": TRUE" );
                        exit;
                    } else {
                        show_debug_message("NE" + string(i) + ": false" );
                    }
                    
                }
            }
            
            // NW
            for(var i = 0; i < xradius; i++) {
                for(var ii = 0; ii < yradius; ii++) {
                    newtilex = tileX - i; 
                    newtiley = tileY - ii;
                    
                    tile = global.mapArray[@newtiley];
                    
                    if(tile[@newtilex] == tilecheck) {
                        return true;
                        show_debug_message("NW " + string(i) + ": TRUE" );
                        exit;
                    } else {
                        show_debug_message("NW" + string(i) + ": false" );
                    }
                    
                }
            }
}
 
Last edited:

TheouAegis

Member
If the radius is supposed to be circular, a tile is within the radius is abs(x)+abs(y)<=radius. Too tired to read your code, but I'd assume that's one of the things you were trying to do.
 

rytan451

Member
Note that return also exists the function. I actually often use just return; on a line by itself to exit a function, since exit might exit the entire event.

When getting from an array, using an array accessor is both less readable and slower (in VM), for no gain. You should be using the array accessor @ only when setting the array.

Why not this:

EDIT: I forgot that the tileX might be less than radius. Oops; fixing.

GML:
var left, right, top, bottom;
left = max(0, tileX - radius + 1);
right = min(array_length(tile[0]), tileX + radius);
top = max(0, tileY - radius + 1);
bottom = min(array_length(tile), tileY + radius);

for (var X = left; X < right; X++) {
    for (var Y = top; Y < bottom; Y++) {
        if (tile[Y][X] == tilecheck) {
            return true;
        }
    }
}

return false;
You could also add a "is the point in a circle" check, like this:

GML:
var left, right, top, bottom;
left = max(0, tileX - radius + 1);
right = min(array_length(tile[0]), tileX + radius);
top = max(0, tileY - radius + 1);
bottom = min(array_length(tile), tileY + radius);

for (var X = left; X < right; X++) {
    for (var Y = top; Y < bottom; Y++) {
        if (tile[Y][X] == tilecheck && point_in_circle(X, Y, tileX, tileY, radius + 0.5) {
            return true;
        }
    }
}

return false;
 
Top