I would like to understand the process of selecting the correct tile from a scaled Surface when I have information about the number of tiles on the x and y axes, the length of the Surface, and also considering the scroll factor

Firstly, I have the following variables:

WIDTH = 640
HEIGHT = 320

Then, I create the base Surface with screen = pg.display.set_mode((WIDTH, HEIGHT), pg.RESIZABLE), and a dummy Surface as follows: dummy = pg.Surface([WIDTH, HEIGHT]).

Next, I create grids using some clever math and a scroll variable (which changes when I press the D button, moving everything backward):

for v in range(MAX_COL):
    # vertical / col
    pg.draw.line(dummy, (0, 0, 0), (TILE_SIZE * v - scroll_x, 0), (TILE_SIZE * v - scroll_x, HEIGHT))
    # horizontal / row
for h in range(MAX_ROW):
    pg.draw.line(dummy, (0, 0, 0), (0 - scroll_x, TILE_SIZE * h), (MAX_COL * TILE_SIZE - scroll_x, TILE_SIZE * h))

Finally, I scale it (using tw and th, calculated dimensions to maintain aspect ratio, but for now, it can be anything):

f = pg.transform.scale(s, (tw, th))
screen.blit(f, (pad_x, pad_y)) # center the window

Now, I want to choose a tile so that when I click it, it shows on which field I currently am. I achieve this by dividing my mouse X and Y coordinates from pg.mouse.get_pos() with the size of a scaled tile, and the result looks something like this:

enter image description here

Now I can go ahead and print this tile as a tuple - (2, 2)

But the problem comes when I move with my map and everything changes its position:

enter image description here

To select a tile like this, I would normally use my scroll variable and manipulate it (such as adding that information to the mouse x coordinate). However, it seems a bit tricky because when I scale everything, my scroll isn't accurate anymore, at least not for working with a mouse. So, I am wondering if someone knows how to maintain my coordinate system while also considering my scroll factor. For example here Id like to get (2, 2) as well but thats not what I get


1 Answer 1


You must apply the inverse of the draw operations in reverse order to the mouse position.

(mx,my) = pg.mouse.get_pos()
mx -= pad_x
my -= pad_y # undo blit center offset
mx /= tw
my /= th # undo the scaling

# mx and my is now in dummy space screen coordinates(not scrolled)

# Scroll X and Y are in dummy coordinate space
tile_x = (mx + scroll_x) // TILE_SIZE
tile_y = (my + scroll_y) // TILE_SIZE

# tile_x is equal to the original h value of grid square under the mouse
# tile_v is equal to the original v value of grid square under the mouse

Affine transformations(translations, i.e. +/- on X,Y,Z,W) are non-linear in nature.

You can build a complete transformation matrix for drawing operations and invert the matrix to give a single operation to undo the screen mouse to source space.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .