Handling clicks on overlapping objects in pygame

Viewed 244

I am building a very simple prototype of an isometric game using pygame.

As I am really new to pygame and game development, I am not really sure how to handle clicking on multiple objects that have overlapping rects. The game has tiles of dirt "stacked" in a way that they appear as a single block of land. The player should be able to click each tile independently.

Can you show me how to do this?

enter image description here

1 Answers

The concept is pretty simple:

You store all the draggable objects in a list. Whenever a click is detected on an object:

  1. Find the list index of that object.

  2. Check if any other objects in the list, with index greater than the current object (which means that they are drawn above the current object), are selected. If so, don't call the drag function, and if not, do call it.

  3. Right before we call the function, make sure to reposition the list index of the current object; since we just clicked it, it should be above all other objects, so remove the object from the list, and append it to the end.

Here is an implementation of the concept:

import pygame

pygame.init()
screen = pygame.display.set_mode((500, 500))

objs = []

class Obj:
    def __init__(self, x, y, w, h, color):
        self.rect = pygame.rect.Rect(x, y, w, h)
        self.dragging = False
        self.color = color
        objs.append(self)

    def clicked(self, m_pos):
        return self.rect.collidepoint(m_pos)

    def set_offset(self, m_pos):
        self.dragging = True
        m_x, m_y = m_pos
        self.offset_x = self.rect.x - m_x
        self.offset_y = self.rect.y - m_y

    def drag(self, m_pos):
        m_x, m_y = m_pos
        self.rect.x = m_x + self.offset_x
        self.rect.y = m_y + self.offset_y

    def draw(self):
        pygame.draw.rect(screen, self.color, self.rect)

square1 = Obj(200, 170, 100, 100, (255, 0, 0))
square2 = Obj(150, 300, 100, 100, (0, 255, 0))
square3 = Obj(220, 30, 100, 100, (0, 0, 255))

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
        elif event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:
                for square in objs:
                    if square.clicked(event.pos):
                        o = objs[objs.index(square)+1:]
                        if not any(s.clicked(event.pos) for s in o):
                            objs.remove(square)
                            objs.append(square)
                            square.set_offset(event.pos)
        elif event.type == pygame.MOUSEBUTTONUP:
            if event.button == 1:
                for square in objs:
                    square.dragging = False
        elif event.type == pygame.MOUSEMOTION:
            for square in objs:
                if square.dragging:
                    square.drag(event.pos)
    screen.fill((255, 255, 255))
    for square in objs:
        square.draw()
    pygame.display.update()

Output:

enter image description here

Related