• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Nearest point outside of grid cell

MeBoingus

Member
Hi all,

I'm working on a little game that has 'floor tiles' aligned to a 64x64 grid.
I need to be able to click inside of any specific cell in the grid, and have my object create a path to it.
That is easy enough. It doesn't require my little pigeon brain to do maths.

The problem is that I now want the object to create the path with the last point being as close to the perimeter of the cell as possible, before crossing into it.

EDIT: Basically I need to create a path that gets as close to the grid cell as possible, without entering it. Almost as if I wanted to be able to have the object 'collide' with it.


My way of describing this sucks, so here's my code thus far, and a poor illustration of what I mean:

GML:
if (mouse_check_button_pressed(mb_left))
{
    path_clear_points(myPath);
    path_add_point(myPath, x, y, 100);
    path_add_point(myPath, mouse_x, mouse_y, 100);

    gridX = floor(path_get_point_x(myPath, 1) / 64) * 64;
    gridY = floor(path_get_point_y(myPath, 1) / 64) * 64;

    var tX = path_get_point_x(myPath, 1);
    var tY = path_get_point_y(myPath, 1);

    var d = point_direction(tX, tY, path_get_point_x(myPath, 0), path_get_point_y(myPath, 0));
    path_change_point(myPath, 1, tX + lengthdir_x(64, d), tY + lengthdir_y(64, d), 100);
}
As you can see, my code DOES ensure that the point is "outside" of the grid cell, by placing it 64 pixels away from that position. I need to somehow calculate how far the point inside of the cell is from perimeter of the cell it's in, and then set adjust the point's position by that amount, in that direction.

Here's the above-mentioned poor illustration:

Poor Illustration.png

The red box is our object.
The X is the final position on our path.
The blue line is where the object should end up.
The purple line where the object does end up, or more specifically the distance I need to calculate.


Any help would be greatly appreciated. If you know of a better way to achieve this, throw your ideas at me by all means.
 
Last edited:
x_diff = end position x (pseudo code) mod 64

If I'm understanding you correctly, this would tell you the difference between the x coordinate of the end point and the grid cell it has crossed into.

mod takes a number, divides it by another number (64 being the size of cells) up to the point where it fits whole, and then only returns the value that remains.

Say you did 200 mod 64: it would return a value of 8, as 64 goes into 200 three times (192) and then you are left with the bit that doesn't fit. Then you want to add whatever is the origin offset of the object to this value, and subtract from, or add it to, the end point which would see it placed exactly up against the edge of the cell.
 

MeBoingus

Member
x_diff = end position x (pseudo code) mod 64

If I'm understanding you correctly, this would tell you the difference between the x coordinate of the end point and the grid cell it has crossed into.

mod takes a number, divides it by another number (64 being the size of cells) up to the point where it fits whole, and then only returns the value that remains.

Say you did 200 mod 64: it would return a value of 8, as 64 goes into 200 three times (192) and then you are left with the bit that doesn't fit. Then you want to add whatever is the origin offset of the object to this value, and subtract from, or add it to, the end point which would see it placed exactly up against the edge of the cell.
I believe this would just result in the new position being the very top left of the grid cell. Using modulo in this way would basically be rounding this position to the coordinates of the specified grid cell.

Here's the code I've used with your idea in mind:

GML:
if (mouse_check_button_pressed(mb_left))
{
    path_clear_points(myPath);
    path_add_point(myPath, x, y, 100);
    path_add_point(myPath, mouse_x, mouse_y, 100);
    
    gridX = floor(path_get_point_x(myPath, 1) / 64) * 64;
    gridY = floor(path_get_point_y(myPath, 1) / 64) * 64;
    
    var tX = path_get_point_x(myPath, 1);
    var tY = path_get_point_y(myPath, 1);
    
    var pmx = path_get_point_x(myPath, 1) % 64;
    var pmy = path_get_point_y(myPath, 1) % 64;
    
    var ox = x % 64;
    var oy = y % 64;
    
    path_change_point(myPath, 1, tX + ox - pmx, tY + oy - pmy, 100);   
}

Here's a screenshot of the resulting path (pink line) that's generated:

Poor Illustration 2.png

I've drawn the position clicked (green X) onto the screenshot, as well as the EXPECTED outcome (yellow line).
 
The only thing I was applying it to is the x position, as I assumed you would keep the same final y position.

1) Get the difference in pixels between "end pos x " and the grid cell edge
2) Add the origin x offset of the object to this difference (my bad, I guess, that I didn't point out these are x specific)
3) Take that value away from end pos x (if to the left) and it should be placing the origin in the right spot for it to be before the grid cell. This would change if the object was to the right of end pos x etc, but it would still be the same process - just with slightly altered values

Only the x position is changed in my example, as your description only seemed to ask for that. To do the y position as well would still be the same thing, but obviously done using the y position and the y origin offsets.
 
Last edited:

MeBoingus

Member
The only thing I was applying it to is the x position, as I assumed you would keep the same final y position.

1) Get the difference in pixels between "end pos x " and the grid cell edge
2) Add the origin x offset of the object to this difference (my bad, I guess, that I didn't point out these are x specific)
3) Take that value away from end pos x (if to the left) and it should be placing the origin in the right spot for it to be before the grid cell. This would change if the object was to the right of end pos x etc, but it would still be the same process - just with slightly altered values

Only the x position is changed in my example, as your description only seemed to ask for that. To do the y position as well would still be the same thing, but obviously done using the y position and the y origin offsets.
I'm struggling to understand what you mean when you say "origin x offset of the object".

The remainder of your process makes sense, but I'm just not sure where the 'origin x offset' value is supposed to come from.


Code (I've interpreted 'origin x offset' as 'the offset of the object within it's own cell'):
GML:
    var origX = path_get_point_x(myPath, 1);
    var origY = path_get_point_y(myPath, 1);
    
    var xDiff = origX mod 64;
    var yDiff = origY mod 64;
    // 1) Get the difference in pixels between "end pos x " and the grid cell edge
    
    
    var objX = x mod 64;
    var objY = y mod 64;
    
    var finalX = origX - (objX + xDiff);
    var finalY = origY - (objY + yDiff);
    // 2) Add the origin x offset of the object to this difference
    
    path_change_point(myPath, 1, finalX, finalY, 100);
 
You may have the origin of your object (if it has a sprite) set to be the centre, or it might not be aligned like that and so you would need to know what the left / right widths are.

dist left = sprite_get_xoffset(sprite_index);
dist_right = sprite_width - dist_left;

if the desired path end is to the left side of the end point:

new_x = end_point_x - (dist_right + (end_point_x mod 64)); // hopefully that code is figured out right
new_y = whatever // if you even alter it?

if the desired path end is to the right side of the end point:

new_x = ((end_point_x div 64) + 1) * 64) + dist_left;

div works differently from mod, in that it returns the number of times a value can go into another value. It's initial return will be the column of which end_point_x falls under, and then 1 is added to that value. Times that by 64 and you get the beginning of the next column. By adding dist left to that, you get the point which would see the path ending with the object placed just at the edge of the previous column to end_position_x (as start to end is going left)
 
Top