Click detection happening multiple times per click

Question:

Whenever a user clicks on a point in the map, the click is registered more than once. Obviously this is not ideal as it could lead to multiple inputs not being registered the correct amount of times.

I have a put a variable "clicked" in the logic, which works in other programs, but here it does not work and it still registers the click more than once.

Main Code:

import pygame
from world import World







pygame.init()

screen_width = 1500
screen_height = 650

screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption('Grid Wars INDEV')


world = World(screen)
tile_size = 50
lineAmount = 1300/50
def draw_grid():
    for line in range(1,25):
        pygame.draw.line(screen, (218,165,32), (200, line * tile_size), (1350, line * tile_size), 2)
        keyline = line + 3
        pygame.draw.line(screen, (218,165,32), (keyline * tile_size, 0), (keyline * tile_size, 650), 2)
        
        




run = True
while run:
    screen.fill("red")
    world.draw()
    draw_grid()
    pygame.draw.line(screen, (218,165,32), (200,5), (1350,5), 10)
    pygame.draw.line(screen, (218,165,32), (200,645), (1350, 645), 10)
    pygame.draw.line(screen, (218,165,32), (200,0), (200, 650), 10)
    pygame.draw.line(screen, (218,165,32), (1350,0), (1350, 650), 10)
    action = world.isClicked()
    if action[0] == True:
        print('Hello World')
        print(action[1])
        




    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    pygame.display.update()

pygame.quit()

Class Code:

import pygame
from button import Button

class World:
    def __init__(self, screen) -> None:
        self.name_list = []
        self.screen = screen
        self.clicked = False
        self.action = False
        map_data = [
       [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
       [1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1],
       [1,0,0,0,0,1,0,1,1,1,0,1,1,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1],
       [1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
       [1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
       [1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
       [1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
       [1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
       [0,1,1,1,1,1,0,0,0,1,1,0,0,1,1,1,1,0,0,0,0,0,1],
       [1,1,1,1,1,1,1,0,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1]
        ]
        ocean_img = pygame.image.load('ocean.png')
        grass_img = pygame.image.load('grass.png')
        row_count = 0
        for row in map_data:
            column_count = 0
            for tile in row:
                if tile == 1:
                    img = pygame.transform.scale(ocean_img, (50,50))
                    self.img_rect = img.get_rect()
                    self.img_rect.x = column_count * 50 + 200
                    self.img_rect.y = row_count * 50 
                    tile = (img, self.img_rect,'ocean')
                    self.name_list.append(tile)
                    
                    
                if tile == 0:
                    img = pygame.transform.scale(grass_img, (50,50))
                    self.img_rect = img.get_rect()
                    self.img_rect.x = column_count * 50 + 200
                    self.img_rect.y = row_count * 50 
                    tile = (img, self.img_rect,'grass')
                    self.name_list.append(tile)
                
                column_count += 1
            row_count += 1
    def draw(self):
        for tile in self.name_list:
            self.screen.blit(tile[0], tile[1])
    def isClicked(self):
        self.clicked = False   
        pos = pygame.mouse.get_pos()
        for tile in self.name_list:
            
            if tile[1].collidepoint(pos):
                if pygame.mouse.get_pressed()[0] == 1 and self.clicked == False:
                        self.clicked = True
                        self.action = True
                if pygame.mouse.get_pressed()[0] == 0:
                    self.clicked = False
                    self.action = False
        return self.action, tile[2]
 
    
Asked By: Aditya Bhadra

||

Answers:

Actually you don’t detect clicks, but you detect when the mouse button is held down and the mouse hovers over a tile. Use the MOUSEBUTTONDOWN event to detect clicks (see Pygame mouse clicking detection). Note that if pygame.event.get() is called in multiple event loops, only one loop receives the events, but never all loops receive all events. As a result, some events appear to be missed. You have to get the events once per frame and use them in multiple loops or pass the list of events to functions and methods where they are handled.

Also, you must break the loop or return the function if you detect a click because you want to get the result of the clicked tile, not the last tile in the loop:

class World:
    # [...]

    def isClicked(self, event_list):

        for event in event_list:
            if event.type == pygame.MOUSEBUTTONDOWN:
                for tile in self.name_list:    
                    if tile[1].collidepoint(event.pos):
                        if event.button == pygame.BUTTON_LEFT:
                            return True, tile[2]
                       if event.button == pygame.BUTTON_RIGHT:
                            return False, tile[2]
        return False, None
while run:

    event_list = pygame.event.get()
    for event in event_list :
        if event.type == pygame.QUIT:
            run = False

    screen.fill("red")
    world.draw()
    draw_grid()
    pygame.draw.line(screen, (218,165,32), (200,5), (1350,5), 10)
    pygame.draw.line(screen, (218,165,32), (200,645), (1350, 645), 10)
    pygame.draw.line(screen, (218,165,32), (200,0), (200, 650), 10)
    pygame.draw.line(screen, (218,165,32), (1350,0), (1350, 650), 10)
    action = world.isClicked(event_list)
    if action[0] == True:
        print('Hello World')
        print(action[1])
        
    pygame.display.update()

pygame.quit()
Answered By: Rabbid76
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.