GML [Solved] Getting orthogonal cell co-ordinates?

hdarren

Member
I'm making a small strategy game on an orthogonal grid as you can see in the image below where each square is 24x11 pixels.

Untitled-1.png

I'm trying to get the center pixel x/y co-ordinate for a specific tile that the mouse cursor is over so that I can do things like create a spell effect in the middle of the square, but I'm having a problem getting the precise x/y position because of how the square rows are offset.

I'm currently using the following code.

GML:
vx = round(x/24) *24;
vy = round(y/6);
if is_multiple(vy,2) {vx += 12;}
vy *= 6;
So this gets the current mouse pointer's x/y co-ordinate and attempts to round it to the central point of a grid square giving me the vx/vy variables for that (which you can see below where it shows an outlinded cell). But as you can see in the image below there's a problem with the offset row where it jumps too far to the right once it goes over the half-way point of a cell.

[gif]

I can't seem to figure out how to get the correct cell co-ordinates. Can anybody help with this?
 
Last edited:
My advice: don't hardcode the position, use the tile sprite width, height and x/y offset tyo calculate your stuff.
Here's how I roughly do it. First, store on your map the summits coordinates of the cell and it's origin (very important)
Since you cant find a point in a rotated rectangle, I splice it in two triangles, using the summit coordinates of the tile.
Not the most efficient way to do it, but totally usable

GML:
function get_mouse_grid_coord(){
    var _map_width = array_length(global.grid);
    var ptx, pty, plx, ply, prx, pry, pbx, pby;                        //Summits of my tile (PointLeftX, PointBottomY, etc...)
    for(var i=0; i<_map_width;i++){
        for(var j=0; j<_map_width;j++){
            ptx = global.grid[@i][@j][$"coord_summit"][$"ptx"];
            pty = global.grid[@i][@j][$"coord_summit"][$"pty"];
            prx = global.grid[@i][@j][$"coord_summit"][$"prx"];
            pry = global.grid[@i][@j][$"coord_summit"][$"pry"];
            plx = global.grid[@i][@j][$"coord_summit"][$"plx"];
            ply = global.grid[@i][@j][$"coord_summit"][$"ply"];
            pbx = global.grid[@i][@j][$"coord_summit"][$"pbx"];
            pby = global.grid[@i][@j][$"coord_summit"][$"pby"];
     
            if( point_in_triangle(mouse_x, mouse_y, ptx, pty, plx, ply, prx, pry) || point_in_triangle(mouse_x, mouse_y, pbx, pby, plx, ply, prx, pry)){
                global.mouse[$"mouse_grid_x"] = i;
                global.mouse[$"mouse_grid_y"] = j;
                exit;
            }        
        }
    }
}

GML:
function tile_summit_coord(_center_x, _center_y, _sprite) constructor{
    var _y_off = sprite_get_yoffset(_sprite);
    var _x_off = sprite_get_xoffset(_sprite);
   
    ptx = _center_x;                //Top
    pty = _center_y - _y_off;
    plx = _center_x - _x_off;        //Left  
    ply = _center_y;
    prx = _center_x + _x_off;        //Right
    pry = _center_y;
    pbx = _center_x;                //Bottom
    pby = _center_y + _y_off;
}


function init_cell(_grid_x, _grid_y, _height, _depth_row, _x, _y, _sprite) constructor{  
    grid_x = _grid_x;
    grid_y = _grid_y;
    center_x = _x;
    center_y = _y;
    height = _height;
    depth_row = _depth_row;
    unit_in_cell = NONE;
    coord_summit = new tile_summit_coord(_x, _y, _sprite);
}

function new_map(_size_side, x0, y0, _sprite_index){
    global.grid = [];
    var _map_width = _size_side;
    var _sprite = _sprite_index;
    var _y0 = y0;
    var _x0 = x0;
    var _y_off = sprite_get_yoffset(_sprite);
    var _x_off = sprite_get_xoffset(_sprite);
    var _xx, _yy;

    for(var i=0; i<=_map_width;i++){
        for(var j=0; j<=_map_width;j++){          
                _xx = _x0 - (j*_x_off) + (i*_x_off);
                _yy = _y0+(i*_y_off) + (j*_y_off);
                global.grid[i][j] = new init_cell(i, j, 0, (i+j), _xx, _yy, spr_tile);
        }          
    }
}
 
Last edited:

WilloX

Member
Hi i think a can help (i am working on an iso grid based project myself).
I have a function that takes the room coordinates and returns the corresponding grid positions:

GML:
function xy_to_ij(xx, yy){
    var xoff = 0;//ds_grid_width(global.grid) * (tile_width >> 1);
    var yoff = 0;//tile_height >> 1;
    //the x/y-offs should be 0 in your case i guess

    var j = (((yy - yoff) / (tile_height >> 1)) - ((xx - xoff) / (tile_width >> 1))) / 2;
    var i = (xx - xoff) / (tile_width >> 1) + j;
   
    return([round(i), round(j)])
}

function ij_to_xy(i, j){
    //that is just the function that does the reverse thing
    var xoff = 0; //ds_grid_width(global.grid) * (tile_width >> 1);
    var yoff = 0; //tile_height >> 1;
    // again 0^^
    var k;
   
    k[1] = yoff + (i + j) * (tile_height >> 1)
    k[0] = xoff + (i - j) * (tile_width >> 1)
   
    return(k)
}
This is how the coordinates are ordered:
iso_gif2.gif
This was edited.
 
Last edited:

hdarren

Member
@WilloX Thank you but what is "ds_grid_width(global.grid)" referring to as it is giving me an error message as the variable isn't set?
 

WilloX

Member
@WilloX Thank you but what is "ds_grid_width(global.grid)" referring to as it is giving me an error message as the variable isn't set?
I forgot - this is the grid that stores information of every tile (in my case the grid is the "level" itself).
Lets say you want a field of 32x32 iso-squares. Then have a grid of that size where grid[# 0,0] <=> the very top tile, ..., grid[# 31, 31] the very bottom tile.

edit:
if you dont want a grid the xoff; yoff variables are constant and are just the in game coordinates of the very top tile
 
Last edited:

hdarren

Member
I can't get it working sadly.

This is the code I'm using in a script called get_cell_pos().

GML:
var tile_height = 24;
var tile_width = 12;

var j = ((y / (tile_height >> 1)) - (x / (tile_width >> 1))) >> 1;
var i = (x / (tile_width >> 1) + j);

vx = round(i);
vy = round(j);
Then in the draw event that just attempts to draw an outline marker around the correct cell at the cell's center I have this code.

GML:
get_cell_pos();

draw_sprite_ext(iFlr_Marker,0,vx,vy,1,1,0,-1,1);

window_set_caption("x:"+string(vx)+" / y:"+string(y)+" /// vx:"+string(vx)+" / vy:"+string(vy));
Then you can see in the gif below moving the crosshair horizontally seems to affect the vy variable which it shouldn't do. I think the vx variable is working fine though. I can't figure out what the ">>" does so I'm having trouble wrapping my head around the code.

[gif]
 
Last edited:

WilloX

Member
Ill look over it once i'm home. (">> 1" is the bitshift to the right by 1 - i use it instead of "div 2" but it does the same)
 

WilloX

Member
Hi again,

So i made some errors in the makeshift code above (sorry about that) but now it works:
iso_gif.gif
Ill edit the code i posted^^
 

hdarren

Member
@WilloX Sorry I'm not having much luck getting this working in my game correctly. I'm looking to just get the central x/y position of the current cell hovered over. So in the image below for example, hovering the mouse over cell A would return an x position of 24 and a y position of 6, while hovering over cell B would return an x position 36 and a y position of 11.

Untitled-1.png

I tried implementing your code but am having problems.

Here's the script to get the vx/vy position based on the mouse pointer object's x/y position.

GML:
var tile_height = 24;
var tile_width = 12;

var j = ((y / (tile_height >> 1)) - (x / (tile_width >> 1))) / 2;
var i = x / (tile_width >> 1) + j;

ii = round(i);
jj = round(j);

vx = (ii - jj) * (tile_width >> 1);
vy = (ii + jj) * (tile_height >> 1);
You can see on the gif below some rows show fine but I can't seem to figure out how to get it to stick to the grid pattern correctly on the image above. The floor segments should line up neatly rather than overlapping.

[gif]
 
Last edited:
Top