pythonpygameprojectile

How do I continuously trigger an action at certain time intervals? Enemy shoots constant beam instead of bullets in pygame


Trying to make an enemy in pygame that shoots bullets in a straight line in pygame. I've managed to make the enemy shoot, but it shoots a constant beam of bullets instead of spacing them out. Is there any way to space out the bullets?

This is the class for the enemy

class Boss(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((100, 70))
        self.image.fill(white)
        self.rect = self.image.get_rect()
        self.rect.centerx = WIDTH / 2
        self.rect.y = (WIDTH / 2) - 500
        self.speedy = 3

    def update(self):
        self.rect.y += self.speedy
        if self.rect.y >= 30:
            self.rect.y = 30

    def shoot(self):
        bossbullet = Bossbullet(self.rect.centerx, self.rect.bottom)
        all_sprites.add(bossbullet)
        bossbullets.add(bossbullet)


class Bossbullet(pygame.sprite.Sprite):
    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((10, 20))
        self.image.fill(white)
        self.rect = self.image.get_rect()
        self.rect.bottom = y
        self.rect.centerx = x
        self.speedy = -10

    def update(self):
        self.rect.y -= self.speedy

        if self.rect.bottom < 0:
            self.kill()

all_sprites = pygame.sprite.Group()
boss = Boss()
all_sprites.add(boss)
bossbullets = pygame.sprite.Group()

this is the loop in which the game runs and the enemy shoots

running = True
while running:

    clock.tick(FPS)
    if boss.rect.y >= 30:
        boss.shoot()

Solution

  • I recommend to use a timer event. Use pygame.time.set_timer() to repeatedly create an USEREVENT. e.g.:

    milliseconds_delay = 500 # 0.5 seconds
    bullet_event = pygame.USEREVENT + 1
    pygame.time.set_timer(bullet_event, milliseconds_delay)
    

    Note, in pygame customer events can be defined. Each event needs a unique id. The ids for the user events have to start at pygame.USEREVENT. In this case pygame.USEREVENT+1 is the event id for the timer event, which spawns the bullets.

    Create a new bullet when the event occurs in the event loop:

    running = True
    while running:
    
        clock.tick(FPS)
    
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
    
             elif event.type == bullet_event:
                 if boss.rect.y >= 30:
                     boss.shoot()
    

    is there any way to make it so the enemy pauses for a while after..let's say 5 shots, then starts shooting again after the pause

    The timer event can be stopped by passing 0 to the time parameter. e.g.:

    delay_time = 500  # 0.5 seconds
    pause_time = 3000 # 3 seconds
    bullet_event = pygame.USEREVENT + 1
    pygame.time.set_timer(bullet_event, delay_time)
    
    no_shots = 0
    
    running = True
    while running:
    
        clock.tick(FPS)
    
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
    
             elif event.type == bullet_event:
                 if boss.rect.y >= 30:
                     boss.shoot()
    
                     # change the timer event time
                     if no_shots == 0:
                         pygame.time.set_timer(bullet_event, delay_time)
                     no_shots += 1
                     if no_shots == 5:
                         pygame.time.set_timer(bullet_event, pause_time)
                         no_shots = 0
    
        killed = # [...] set state when killed
    
        # stop timer
        if killed:
            pygame.time.set_timer(bullet_event, 0)