0

I’m making a Space Invaders game, and I’m having trouble with the home and pause screens. The main thing I’m unable to do is going back to the former from the latter, because the home screen button in the pause screen and the start game button in the home screen are located at roughly the same coordinates. That means that whenever I click to go back to the home screen from the pause screen, Pygame keeps the pygame.mouse.get_pressed()[0] instance as True and starts the game automatically, as if I’ve clicked to start it from the home screen as well.

To solve that issue, I decided to use collidepoint() to try and make Pygame understand that the collision was in the rect from the pause screen, not in the one from the home screen (though it doesn’t change anything because once I’m back to the home screen, Pygame detects a collision again and clicks the start game button).

But now I’ve ran into another issue: collidepoint() is returning False when it should return True. The x coordinates of the start game button are 149 -> 621 and the y coordinates are 370 -> 403. Any point located inside that interval should return a collision, right? But for some points, it just returns False, for example: collidepoint(458, 389).

In my game, I’m blitting both the home and the pause screens over a dark rectangle that is smaller than the game window:

Home screen

Pause screen

What I’ve found out is that whenever I do that (blitting a rect A over another rect B), Pygame defines the coordinates of the rect A based on the rect B instead of the entire game screen, while it doesn’t do the same for the mouse. So, in the example above, the point (458, 389) is outside of the “CLICK OR PRESS ENTER TO START” rect because this rect y axis starts at 355 of the background rect (370 of the screen) and has a height of 33, ending on 388 (403 of the screen).

Here's a snippet of my code:

class Pause(pygame.sprite.Sprite):
    
        def __init__(self):
            pygame.sprite.Sprite.__init__(self)
            self.paused = False
            
            # Pause screen
            self.image = pygame.Surface((760, 570), pygame.SRCALPHA)
            self.image.fill(MENU_BACKGROUND)
            self.rect = self.image.get_rect()
            self.rect.center = screen_rect.center
            
            title_font = pygame.font.Font(FONT_FILE, 96)
            title_surface = title_font.render('PAUSED', True, (255, 255, 255))
            title_rect = title_surface.get_rect()
            title_rect.center = self.rect.center
            
            link_font = pygame.font.Font(FONT_FILE, 48)
            
            # Home screen button
            main_surface = link_font.render('MAIN MENU', True, (255, 255, 255))
            self.main_rect = pygame.Rect((310, 365), (215, 61))
            self.main_rect.midtop = title_rect.midbottom

            self.image.blits(((title_surface, title_rect), (main_surface, self.main_rect)))

        def update(self):            
            if pygame.mouse.get_pressed()[0]:
                main_click = self.main_rect.collidepoint(pygame.mouse.get_pos())

                if main_click:
                    global game_start
                    game_start = False
                    self.paused = False
                    render_sprites.empty()
                    render_sprites.add(main_screen)

        def pause(self):
            player.dx = 0
            render_sprites.empty()
            render_sprites.add(self)
        
        def resume(self):
            render_sprites.empty()
            
            # Redraws the gameplay sprites
            if bullet.shot:
                render_sprites.add(player, bullet, score, enemies) # Redraws the bullet if it was moving before pausing
            else:
                render_sprites.add(player, score, enemies)
            
            self.paused = False
            
class MainScreen(pygame.sprite.Sprite):
    
        def __init__(self):
            pygame.sprite.Sprite.__init__(self)
            self.image = pygame.Surface((760, 570), pygame.SRCALPHA)
            self.image.fill(MENU_BACKGROUND)
            self.rect = self.image.get_rect()
            self.rect.center = screen_rect.center
            self.last = pygame.time.get_ticks()
            self.cooldown = 400
            self.add(render_sprites)
            
            # Title text
            title_font = pygame.font.Font(FONT_FILE, 96)
            self.title_image = title_font.render('SPACE INVADERS', True, (255, 255, 255))
            self.title_rect = self.title_image.get_rect()
            self.title_rect.center = screen_rect.center

            link_font = pygame.font.Font(FONT_FILE, 32)
            
            # Start game blinking button
            self.start_text = link_font.render('CLICK  OR  PRESS  ENTER  TO  START', True, (255, 255, 255))
            self.start_rect = pygame.Rect((149, screen_rect.top + 370), (472, 33))
            self.start_rect.center = (385, 371.5)
            self.no_text = pygame.Surface(self.start_rect.size, pygame.SRCALPHA)
            self.no_text.fill((0, 0, 0, 0))
            self.start_surfaces = cycle([self.start_text, self.no_text])

            # Options screen button
            self.opt_surface = link_font.render('OPTIONS', True, (255, 255, 255))
            self.opt_rect = pygame.Rect((149, 388), (126, 33))
            self.opt_rect.center = (385, 404.5)

            self.image.blits(((self.title_image, self.title_rect),
                              (self.start_text, self.start_rect),
                              (self.opt_surface, self.opt_rect)))
            
        def update(self):
            global game_start
            if game_start:
                self.kill()
            else:
                # Blinking text
                now = pygame.time.get_ticks()
                if (now - self.last) >= self.cooldown:
                    self.image.fill(MENU_BACKGROUND)
                    self.image.blits(((self.title_image, self.title_rect),
                                      (next(self.start_surfaces), self.start_rect),
                                      (self.opt_surface, self.opt_rect)))
                    self.last = pygame.time.get_ticks()
                    
                rect_click = self.start_rect.collidepoint(pygame.mouse.get_pos())
                
                # Starts game
                if pygame.key.get_pressed()[pygame.K_RETURN] or (
                        pygame.mouse.get_pressed()[0] and
                        rect_click):
                    game_start = True
                    render_sprites.add(player, enemies, score)

TL;DR: I’m having two issues:

  1. By clicking on the home screen menu button on the pause screen I’m accidentally clicking on the start game button because both buttons are located at the same place;
  2. collidepoint() is returning False when it should return True.

0 Answers0