Grave
Grave

Reputation: 68

Pygame how to detect clicks from a list of images

For my levels screen I use images for each level button, there are 15 on a page. I was able to blit them all to the screen in a nice layout using some iteration and math, I have been trying to figure out a way to do this with the click detection aswell. But I do not want to type "var = get_rect" 15 times a page.

All of the images are in a list for iteration,

self.levels_p1 = [self.l1, self.l2, self.l3, self.l4, self.l5,
                     self.l6, self.l7, self.l8, self.l9, self.l10,
                     self.l11, self.l12, self.l13, self.l14, self.l15,]

and are added to the screen in a 5 x 3 like this,

            for i, lvl in enumerate(self.levels_p1, start=1):
                x = ((WIDTH - 100) * (i % 5) // 6) + 17
                y = HEIGHT // 10 + ((i // 5) * 125)
                if i % 5 == 0:
                    x = ((WIDTH - 100) * 5 // 6) + 17
                    y = HEIGHT // 10 + (((i // 5) - 1) * 125)
                self.screen.blit(lvl, (x, y))
                if self.level_unlocked < i:
                    self.screen.blit(self.level_shade, (x, y))

And I have been detecting clicks like this,

            mousepos = pg.mouse.get_pos()

            for event in pg.event.get():
                if event.type == pg.QUIT:
                    pg.quit()
                if event.type == pg.MOUSEBUTTONDOWN:
                    #to menu
                    if self.back_rect.collidepoint(*mousepos):
                        on_levels = False
                        self.swipe.play()
                        self.start()
                    #to levels2 page
                    if self.arrow_rect.collidepoint(*mousepos):
                        on_levels = False
                        self.swipe.play()
                        self.levels_page2()
                    #to level 1
                    if self.l1_rect.collidepoint(*mousepos):
                        on_levels = False
                        self.swipe.play()
                        self.load_level(1)

But that will only work for all the levels if I manually define a rect for all of the buttons, which is what I am trying to avoid.

I was wondering if there is a good way to detect the clicks on each and every one of these buttons? Similarly to how I displayed them in the 2nd code bit.

Much appreciated.

Upvotes: 3

Views: 123

Answers (3)

Grave
Grave

Reputation: 68

        mousepos = pg.mouse.get_pos()
        lvls = []

        for i, lvl in enumerate(self.levels_p1):
            #x, y topleft for 5x3 grid with easement and centered
            x = ((WIDTH - 100) * (i % 5) // 5) + 110
            y = HEIGHT // 10 + ((i // 5) * 125)
            #add to screen
            temp = self.screen.blit(lvl, (x, y))
            #if not unlocked
            if self.level_unlocked < i:
                #darken
                self.screen.blit(self.level_shade, (x, y))
            #if unlocked
            else:
                #enlarged version if hovering over and unlocked
                if temp.collidepoint(*mousepos):
                    self.screen.blit(self.levels_1l[i], (x-6, y-6))
                #rect list for click detection
                lvls.append(temp)

        #back button interactive
        if self.back_rect.collidepoint(*mousepos):
            self.screen.blit(self.t_back2, self.back_rect2)  # bigger
        else:
            self.screen.blit(self.t_back, self.back_rect)  # normal
        #arrow button interactive
        if self.arrow_rect.collidepoint(*mousepos):
            self.screen.blit(self.arrowr2, self.arrow_rect2)  # bigger
        else:
            self.screen.blit(self.arrowr, self.arrow_rect)  # normal

        pg.display.flip()
        #all button presses
        for event in pg.event.get():
            if event.type == pg.QUIT:
                pg.quit()
            if event.type == pg.MOUSEBUTTONDOWN:
                #to menu
                if self.back_rect.collidepoint(*mousepos):
                    on_levels = False
                    self.swipe.play()
                    self.start()
                #to levels2 page
                if self.arrow_rect.collidepoint(*mousepos):
                    on_levels = False
                    self.swipe.play()
                    self.levels_page2()
                #to level
                for i, val in enumerate(lvls):
                    #if clicked pos = level pos
                    if lvls[i].collidepoint(*mousepos):
                        on_levels = False
                        self.swipe.play()
                        #level to load
                        self.load_level(i+1)

Upvotes: 1

Anya Precious
Anya Precious

Reputation: 134

if self.arrow_rect.collidepoint(*mousepos)

I don't know what you're packing on the line above. If you want to detect clicks, I think you should get mouse position first. I'll do something like this:

for event in pg.event.get():
            if event.type == pg.QUIT:
                pg.quit()
            if event.type == pg.MOUSEBUTTONDOWN:
                #to menu
                mousepos = pg.mouse.get_pos() #Here lies the magic and no need to unpack
                if self.back_rect.collidepoint(mousepos):
                    on_levels = False
                    self.swipe.play()
                    self.start()
                #to levels2 page
                if self.arrow_rect.collidepoint(mousepos):
                    on_levels = False
                    self.swipe.play()
                    self.levels_page2()
                #to level 1
                if self.l1_rect.collidepoint(mousepos):
                    on_levels = False
                    self.swipe.play()
                    self.load_level(1) 

If that solves your problem please let me know and of it doesn't still let me know!

Edit: Try if/elif block instead of just if.

Upvotes: 1

Rabbid76
Rabbid76

Reputation: 210890

pygame.Surface.blit returns a rectangle with the area of the affected pixels:

self.rect = self.screen.blit(self.level_shade, (x, y))

Alternatively you can get the bounding rectangle of a pygame.Surface by get_rect(). The location of this rectangle is (0, 0). Hence, you have to set the position by a keyword argument:

self.rect = self.level_shade.get_rect(topleft = (x, y)) 

Upvotes: 1

Related Questions