Search code examples
pythonpython-3.xpygame

Is there a way to make sure that two events do not repeat too close together in pygame?


I'm trying to figure out how to make a game with shooting in pygame. This is what I have done so far.

import pygame, sys
from pygame.locals import *

class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.Surface((100, 100))
        self.image.fill(WHITE)
        self.rect = self.image.get_rect(center = (SCREENWIDTH/2, SCREENHEIGHT/2))
    
    def update(self):
        # Make the player follow the mouse
        self.rect.center = pygame.mouse.get_pos()

    def create_bullet(self):
        return Bullet(pygame.mouse.get_pos()[0], pygame.mouse.get_pos()[1])

class Bullet(pygame.sprite.Sprite):
    def __init__(self, pos_x, pos_y):
        super().__init__()
        self.image = pygame.Surface((50, 10))
        self.image.fill(RED)    
        self.rect = self.image.get_rect(center = (pos_x, pos_y))

    def update(self):
        self.rect.x += 5
        if self.rect.x >= SCREENWIDTH - 10:
            self.kill() # Destroy the sprite 

# WINDOW SETUP
SCREENWIDTH = 800
SCREENHEIGHT = 700
SCREEN = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT))
pygame.display.set_caption('Shooting')
pygame.mouse.set_visible(False)

# FPS AND CLOCK
FPS = 60
CLOCK = pygame.time.Clock()

# COLORS
WHITE  = (255, 255, 255)
RED    = (128,   0,   0)
BLUE   = (  0,   0, 128)
YELLOW = (236, 205,   0)

player = Player()
player_group = pygame.sprite.Group()
player_group.add(player)

bullet_group = pygame.sprite.Group()
def main():
    pygame.init()
    main_font = pygame.font.Font('freesansbold.ttf', 32)
    Label = main_font.render("Press SPACE to shoot", True, WHITE)
    # MAIN GAME LOOP
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

        keys = pygame.key.get_pressed()
        if keys[pygame.K_SPACE]:
            bullet_group.add(player.create_bullet())

        # DRAW
        SCREEN.fill((30, 30, 30))
        SCREEN.blit(Label, (10, 10))

        bullet_group.draw(SCREEN)
        player_group.draw(SCREEN)

        player_group.update()
        bullet_group.update()
        
        pygame.display.update()
        CLOCK.tick(FPS)

if __name__ == '__main__':
    main()

It works fine except the fact that when I press space, the bullets come togheter in a row, too close to each other (I want the player shoot as long as I am pressing the space bar, I've already tried to put the if statement in the events handling for loop). How can I "separate" the bullets from each other in order to have a more sensible game? I have also tried this:

keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE]:
    pygame.time.wait(100)
    bullet_group.add(player.create_bullet())

but it doesn't work.


Solution

  • pygame.key.get_pressed() is not an event. Use the KEYDOWN event.

    pygame.key.get_pressed() returns a sequence with the state of each key. If a key is held down, the state for the key is True, otherwise False. Use pygame.key.get_pressed() to evaluate the current state of a button and get continuous movement.

    The keyboard events (see pygame.event module) occur only once when the state of a key changes. The KEYDOWN event occurs once every time a key is pressed. KEYUP occurs once every time a key is released. Use the keyboard events for a single action:

    def main():
        # [...]
    
        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
    
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_SPACE:
                        bullet_group.add(player.create_bullet())
    
            # [...]
    

    If you want continuous fire, in which the projectiles can be fired at a certain interval, see How do I stop more than 1 bullet firing at once?.