Search code examples
pythonpython-3.xpygameclick

Pygame collidepoint() not working correctly


I was making a game where you chop down trees and wanted it so that you could only chop down trees within a radius of 50 pixels (approx. 1 tree in each direction) of your position in the game(represented by a square). The problem is, when I tested it, I found that it worked only once, and by that I mean you only have to move to stop the radius barrier from working and you can destroy any tree. Can someone tell me why this is happening and how to fix it? The code is below:

# I'll only put in the bit that makes the bug
# Tree objects are sorted in a Tree class with a method destroy() to destroy the tree
for tree in trees:
    if pygame.mouse.get_pressed()[0] and tree.trunk.collidepoint(pygame.mouse.get_pos()):
        mouse_x, mouse_y = pygame.mouse.get_pos()
        print('clicked tree') # For testing purposes
        if mouse_x < x + 51 and mouse_y < y + 51:
            countdown = 3
            destroy_tree = tree
        elif mouse_x < x + 51 and mouse_y < y - 51:
            countdown = 3
            destroy_tree = tree
        elif mouse_x < x - 51 and mouse_y < y - 51:
            countdown = 3
            destroy_tree = tree
        elif mouse_x < x - 51 and mouse_y < y + 51:
            countdown = 3
            destroy_tree = tree

Solution

  • You have to evaluate whether the coordinate is in a range, in one and the same condition. What you actually do is something like:

    if x < value + 50:
       countdown = 3
    elif x > value - 50:
       countdown = 3
    

    One of the conditions is always fulfilled and at the end countdown is set in any case.

    The condition has to be:

    if x - 51 < mouse_x < x + 51:
        if y - 51 < mouse_y < y + 51:
            countdown = 3
            destroy_tree = tree
    

    Furthermore the algorithm can be simplified by using abs(). For instance:

    mouse_x, mouse_y = pygame.mouse.get_pos()
    for tree in trees:
        if pygame.mouse.get_pressed()[0] and tree.trunk.collidepoint((mouse_x, mouse_y)):
            print('clicked tree') # For testing purposes
    
            dx = mouse_x - x
            dy = mouse_y - y
            if abs(dx) <= 50 and abs(dy) <= 50:
                countdown = 3
                destroy_tree = tree
    

    Alternatively you can compute the Euclidean distance:

    mouse_x, mouse_y = pygame.mouse.get_pos()
    for tree in trees:
        if pygame.mouse.get_pressed()[0] and tree.trunk.collidepoint((mouse_x, mouse_y)):
            print('clicked tree') # For testing purposes
    
            dx, dy = (mouse_x - x, mouse_y - y)
            if dx*dx + dy*dy <= 50*50:
                countdown = 3
                destroy_tree = tree