• 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!

Legacy GM [SOLVED]Snapping sprite to isometric grid

dazza_bo

Member
I've been playing around with isometric lately and learning a lot. One thing I haven't been able to figure out though is snapping to an isometric grid. I'm trying to get a sprite to follow my mouse cursor and snap to the iso grid as I move the cursor around.

I have tried a few different suggestions I have found in these forums and elsewhere but can't get it to work right.

I found this post on the forum which kinda works but it's not snapping exactly to the grid, it's offset:

If I'm understanding things correctly, then you want an isometric grid snap. As long as sprites origins are centered in the middle of the diamonds and mouse_x and mouse_y are greater than 0, then you can use

x = (mouse_x & ~31) + ((mouse_y >> 4 & 1) << 5);
y = (mouse_y & ~15) + ((mouse_x >> 5 & 1) << 4);

This is with no other restrictions (other than a positive mouse_x and mouse_y), so half the sprite would draw outside the room when on the edges. You'd need to instate some other preventative conditions to keep that from happening.

The formula above in slower-but-more-flexible terms:

var tile_half_width = sprite_width/2;
var tile_half_height= sprite_height/2;
var xx = mouse_x div tile_half_width;
var yy = mouse_y div tile_half_height;
x = (xx + (yy & 1)) * tile_half_width;
y = (yy + (xx & 1)) * tile_half_height;

I haven't figured out a working 2-line formula for negative coordinates yet and am starting to think I never will, so restrict your game to positive x and y coordinates.
I assume the problem is where TheouAegis says "As long as sprites origins are centered in the middle of the diamonds" but my sprites are centred at the top of the diamonds:


My code still uses 64w x 32h for the tile dimensions though. Any ideas on what I'd need to change?
 
Hi. Does this work for you?

grid_x = ( mouse_x / 2 + mouse_y ) div 32;
grid_y = ( mouse_y - mouse_x / 2 ) div 32;



I'm assuming you are using the isometric conversion:

var x1 = x0 - y0;
var y1 = (x0 + y0) / 2;
 
Last edited:

dazza_bo

Member
Hi flyingsaucerinvasion, thanks for the reply.

Unfortunately that doesn't work, assuming I use those two variables like so?: draw_sprite(spr_sprite,grid_x,grid_y)

For the isometric conversion I use 4 scripts. 1 script each for converting x and y from screen position to isometric map position and 1 script each for x and y from isometric map back to screen position.

Code:
/// scr_screenXToMapX(screen_X, screen_Y)
return ((argument0 / obj_baseTile.tileWidth) + (argument1 / (obj_baseTile.halfTileHeight)) / 2);
Code:
/// scr_screenYToMapY(screen_X, screen_Y)
return ((argument1 / (obj_baseTile.tileHeight)) - (argument0 / obj_baseTile.halfTileWidth) / 2);
Code:
/// scr_mapXToScreenX(map_X, map_Y)
return (argument0 - argument1) * obj_baseTile.halfTileWidth;
Code:
/// scr_mapYToScreenY(map_X, map_Y)
return (argument0 + argument1) * (obj_baseTile.halfTileHeight);
If you need any more info just let me know.
Cheers
 
what are the values of halfTileWidth and halfTileHeight?

Are your screen to map conversions correct? They seem wrong to me.

x0, y0 would be map position, x, y would be screen position, w and h are your tile half width and height.

//map to screen
x = (x0 - y0) * w
y = (x0 + y0) * h

x / w = x0 - y0
y / h = x0 + y0

x0 = x / w + y0
y0 = y / h - x0

x0 = x / w + y / h - x0
y0 = y / h - x / w - y0

//screen to map
x0 = x / w / 2 + y / h / 2
y0 = y / h / 2 - x / w / 2

oh wait, you use full tile width and height in your screen to map conversion, which would in effect be the same as /w/2 and /h/2. Assuming the values of tile width and height and half width and height are correct.
 
Last edited:

dazza_bo

Member
what are the values of halfTileWidth and halfTileHeight?

Are your screen to map conversions correct? They seem wrong to me.
haha this would not surprise me. Isometric is all new to me and I feel like I kinda just cobbled it all together and it somehow works. The tile dimensions are hardcoded at the moment.
tileWidth = 64, tileHeight = 32. halfTileWidth = 32, halfTileHeight = 16.

x0, y0 would be map position, x, y would be screen position, w and h are your tile half width and height.

//map to screen
x = (x0 - y0) * w
y = (x0 + y0) * h

x / w = x0 - y0
y / h = x0 + y0

x0 = x / w + y0
y0 = y / h - x0

x0 = x / w + y / h - x0
y0 = y / h - x / w - y0

//screen to map
x0 = x / w / 2 + y / h / 2
y0 = y / h / 2 - x / w / 2

oh wait, you use full tile width and height in your screen to map conversion, which would in effect be the same as /w/2 and /h/2. Assuming the values of tile width and height and half width and height are correct.
Do you think I should change my conversion scripts to the ones you've posted here instead?
 
I'm curious, do things in your grid appear to be drawn in the correct place at all?

Actually, no. On further reflection I think your conversion from grid to screen is correct.

I guess my next question is whether you are trying to get the grid cell or the room position of that grid cell?
 
Last edited:

dazza_bo

Member
Sorry mate I should have explained it a bit better in the original post. The tile sprites are stored in a 2D grid and then converted to iso position to be drawn. The screen to map scripts get the x and y positions of the cell in the grid. It all seems to be drawing correctly and I can interact with the grid, like replace a dirt sprite cell with a grass sprite for instance. The only thing that I can't seem to get working is having a sprite follow my cursor and snap to the isometric grid.

Appreciate all the help so far btw.
 

dazza_bo

Member
you just need to convert from "screen" to grid space, and then snap that value to the nearest cell, and convert back into screen space.
As soon as I read this it all clicked and it seemed so simple.
Code:
isox = floor(scr_screenXToMapX(mouse_x,mouse_y));
isoy = floor(scr_screenYToMapY(mouse_x,mouse_y));
xx = scr_mapXToScreenX(isox,isoy);
yy = scr_mapYToScreenY(isox,isoy);

draw_sprite(spr_grass,0,xx,yy)
Works exactly how I hoped it would. Thanks for all your help mate :)
 
Top