Brandyn
Brandyn

Reputation: 1017

Getting World Coordinates with mouse in pygame

I am having trouble updating the mouse position and checking for entity collisions (between the mouse and entity) due to my level scrolling. I have used the camera function from this question: How to add scrolling to platformer in pygame

I have tried to use the camera function on the mouse like this:

def update(self, target, target_type, mouse):
        if target_type != "mouse":
            self.state = self.camera_func(self.state, target.rect)
        else:
            new_pos = self.camera_func(mouse.rect, target.rect)
            mouse.update((new_pos[0], new_pos[1]))
            print mouse.rect

but the mouse.rect is consistently set to 608, 0. Can someone help me with this? The mouse class looks like this:

class Mouse(Entity):

    def __init__(self, pos):
        Entity.__init__(self)
        self.x = pos[0]
        self.y = pos[1]
        self.rect = Rect(pos[0], pos[1], 32, 32)

    def update(self, pos, check=False):
        self.x = pos[0]
        self.y = pos[1]
        self.rect.top = pos[1]
        self.rect.left = pos[0]

        if check:
            print "Mouse Pos: %s" %(self.rect)
            print self.x, self.y

Everytime I click the screen, and pass it through a collision test, it always uses the point on the screen, however I need the point on the map (if that makes sense). For example, the screen size is 640x640. If I click in the top left corner, the mouse position will always be 0,0 however, the actual map coordinates may 320,180 in the top corner of the screen. I have attempted to update everything with the camera and the mouse, and the only real results are when I apply the camera.update function to the mouse, but this stop the player being the cause of the scrolling, so I therefore attempted to update the mouse.rect with this function.

Attempted code:

    mouse_pos = pygame.mouse.get_pos()
    mouse_offset = camera.apply(mouse)
    pos = mouse_pos[0] + mouse_offset.left, mouse_pos[1] + mouse_offset.top
    mouse.update(mouse_pos)
    if hit_block:
        print "Mouse Screen Pos: ", mouse_pos
        print "Mouse Pos With Offset: ", pos
        print "Mouse Offset: ", mouse_offset
        replace_block(pos)

Upvotes: 1

Views: 1254

Answers (2)

sloth
sloth

Reputation: 101122

The camera calculates the screen coordinate by a given world coordinate.

Since the mouse position is already a screen coordinate, if you want to get the tile under the mouse, you have to substract the offset, not add it.

You can add the following method to the Camera class:

def reverse(self, pos):
    """Gets the world coordinates by screen coordinates"""
    return (pos[0] - self.state.left, pos[1] - self.state.top)

and use it like this:

    mouse_pos = camera.reverse(pygame.mouse.get_pos())
    if hit_block:
        replace_block(mouse_pos)

Upvotes: 1

ninMonkey
ninMonkey

Reputation: 7511

When you read the mouse that's screen coordinates. Since you're scrolling, you need world coordinates to check the collisions.

Your render loop simplifies to

# draw: x+offset
for e in self.entities:
    screen.draw(e.sprite, e.rect.move(offset))

which is the same as draw( world_to_screen( e.rect ))

Your click would be collidepoint( screen_to_world( pos ))

# mouseclick
pos = event.pos[0] + offset.left, event.pos[1] + offset.top
for e in self.entities:
    if e.collidepoint(pos):
        print("click:", pos)

Upvotes: 2

Related Questions