I had this same problem for a game that I was writing. I imagine that this problem will differ based on how exactly you implemented you isometric system, but I'll explain how I solved the problem.
I first started with my tile_to_screen function. (I assume that's how you are placing the tiles in the right location in the first place.) This function has an equation to calculate screen_x and screen_y. Mine looked like this (python):
def map_to_screen(self, point): x = (SCREEN_WIDTH + (point.y - point.x) * TILE_WIDTH) / 2 y = (SCREEN_HEIGHT + (point.y + point.x) * TILE_HEIGHT) / 2 return (x, y)
I took those two equations and made them into a system of linear equations. Solve this system of equations in any method you choose. (I used a rref method. Also, some graphing calculators can solve this problem.)
The final equations looked like this:
# constants for quick calculating (only process once) DOUBLED_TILE_AREA = 2 * TILE_HEIGHT * TILE_WIDTH S2M_CONST_X = -SCREEN_HEIGHT * TILE_WIDTH + SCREEN_WIDTH * TILE_HEIGHT S2M_CONST_Y = -SCREEN_HEIGHT * TILE_WIDTH - SCREEN_WIDTH * TILE_HEIGHT def screen_to_map(self, point): # the "+ TILE_HEIGHT/2" adjusts for the render offset since I # anchor my sprites from the center of the tile point = (point.x * TILE_HEIGHT, (point.y + TILE_HEIGHT/2) * TILE_WIDTH) x = (2 * (point.y - point.x) + self.S2M_CONST_X) / self.DOUBLED_TILE_AREA y = (2 * (point.x + point.y) + self.S2M_CONST_Y) / self.DOUBLED_TILE_AREA return (x, y)
As you can see, it's not simple like the initial equation. But it does work nicely for the game I created. Thank goodness for linear algebra!
Update
After writing a simple Point class with various operators, I simplified this answer to the following:
# constants for quickly calculating screen_to_iso TILE_AREA = TILE_HEIGHT * TILE_WIDTH S2I_CONST_X = -SCREEN_CENTER.y * TILE_WIDTH + SCREEN_CENTER.x * TILE_HEIGHT S2I_CONST_Y = -SCREEN_CENTER.y * TILE_WIDTH - SCREEN_CENTER.x * TILE_HEIGHT def screen_to_iso(p): ''' Converts a screen point (px) into a level point (tile) ''' # the "y + TILE_HEIGHT/2" is because we anchor tiles by center, not bottom p = Point(p.x * TILE_HEIGHT, (p.y + TILE_HEIGHT/2) * TILE_WIDTH) return Point(int((p.y - p.x + S2I_CONST_X) / TILE_AREA), int((p.y + p.x + S2I_CONST_Y) / TILE_AREA)) def iso_to_screen(p): ''' Converts a level point (tile) into a screen point (px) ''' return SCREEN_CENTER + Point((p.y - p.x) * TILE_WIDTH / 2, (p.y + p.x) * TILE_HEIGHT / 2)