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

SOLVED Translate position in room to position on gui?

I have a room that is pretty big in size. So naturally I'm using a camera and view. I can pan around, zoom in, zoom out, and resize the window. I've got all that working pretty good. I'm only using view[0] and its default camera.

What I'm trying to achieve:
This game is grid based and it is important that the player is able to see grid lines on the game world. It is easy enough to add a simple repeating background or draw the lines in a few for loops, however this is presenting me with an issue.

The issue:
In this game you can zoom out to view the entire room, or zoom all the way in to view everything 1:1. When viewing anything other than 1:1, the grid lines do not scale well. Some of the line get interpolated to be invisible while others are still visible. While you are actively zooming in or out and the zoom value is continuously changing (this support multi-touch pinch zoom), the grid line produce an effect that could give one an epileptic seizure.

Finally, the part I'm asking for help with:
What I would like to do to solve this is draw the grid line in a for loop, directly to the view surface before the camera and therefore, untied to the my scaling system. My view camera is not snapped to the grid. So how do I draw this aligned with the in-room grid? I'm just a bit stumped on how to translate those positions from the room to the surface so that they line up. I would do more research, but I'm not even sure how to put that into one phrase.

I'll grab some screenshots here soon if any of you want them
 
If you need the lines to always be drawn at the same thickness, untied from the view's scaling and position, you'll want to draw it afterwards, in the draw_gui event. Drawing to the view surface before the camera does it's thing will result in whatever you draw being drawn over by everything else. Drawing to the GUI means no scaling or position transformation will occur.

I'm guessing that when you talked about using draw_line in a for loop, you were drawing the lines over the whole map. Since we're doing it in the draw_gui event now, that's not necessary - we only need to draw the lines that are currently visible on the screen. I'll only go over the vertical lines, but the horizontal will be very similar:

GML:
view_width = camera_get_view_width(view_camera[0]);
view_height = camera_get_view_height(view_camera[0]);
view_x = camera_get_view_x(view_camera[0]);

var dx,dy,vx,vy,startx,starty,vwidth,vcount,i;

vwidth = cell_width * view_zoom;//cell_width is how many pixels wide a grid cell is at a zoom of 1
vcount = view_width / vwidth;

vy = view_height;
dx = vwidth;
for (i = 0; i < vcount; i++){
    draw_line(dx,0,dx,vy);
    dx += vwidth;
}
This draws vertical lines across the screen that scale with the zoom level. Since it's in the draw_gui event, those lines will always be exactly one pixel thick (you could use draw_rectangle() if you need thicker lines). There's still an issue here, which is that the lines won't match the tiles if the camera isn't exactly aligned with the grid. To solve that, we replace one line:

GML:
dx = vwidth;
//replace that with:
dx = vwidth - (view_x mod vwidth);
mod returns the remainder of an integer divided by another integer. So if the camera's X is 72 and your cell_width is 32, 72 mod 32 returns 8. Subtract 8 from 32, and now the drawing will start at 24, the next line will start at 24, and so on. The drawn lines will now be offset to match the grid.

If you wanted to use more stylized grid markings than a simple series of lines, you could use similar code to determine the dimensions and positions of a nineslice sprite.

Of course, this will draw the grid over everything, including characters and items, which could be an issue if there are sprites that exceed the dimensions of the grid cell. Drawing the grid after the terrain, but before everything else, without having the view's scaling applied, would be tricky and implementation would probably be pretty specific to your project. It might be easier to just make sure your terrain's art style clearly communicates the grid.
 
@RhyminGarFunkle
This does solve the mathematical part of this issue for me, and I thank you.
However this doesn't completely solve my issue because in-fact my sprites do exceed the cell limits. Drawing this grid isn't necessary for playing a level in my game. But it is required for the level editor. I do have to draw the lines as you have shown me, but beneath the rest of the room contents. I know this can be done I just haven't needed to do it before. I'm gonna try to apply your method, then see if I can get that below my game elements.
 
The idea that immediately springs to mind is to draw everything under the grid lines as usual, then draw everything else to a surface with the camera's dimensions. In the draw GUI event, draw the grid lines as described, then draw the surface stretched to the width and height of the window.

If it's only for the level editor though, is this complicated drawing scheme really necessary? Players expect that the level editor will be more "workmanlike" than the game proper, and would probably be perfectly happy with a grid that's drawn over everything and can be toggled or faded. To draw the grid in-between, you'll either need to have separate drawing routines for the editor vs the game (at a minimum, everything compensating it's position for drawing to a surface), or you'll need to have everything in the game proper compensate for a feature that will never be used. Really think about if the added headache will be worth it.
 
Well I experimented for awhile and I'm happy with the solution I came up with.
You can use view_set_surface_id to have the view draw to a surface instead of the view port. I'm drawing the lines to the surface outside the draw events. I'm using view[1] to draw the surface. Because view[0] is processed before view[1], the surface is always ready
 
Top