4

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()
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
d'arby
  • 87
  • 6

1 Answers1

2

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)
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • can you explain what's happening on the line ```bullet_event = pygame.USEREVENT + 1 ``` please? – d'arby Oct 03 '19 at 18:25
  • @d'arby Sorry, the link was wrong. In pygame you can define your own events. Each event needs a unique id. The ids for the user events have to start at `pygame.USEREVENT`. `pygame.USEREVENT+1` is the event id for the timer event which spawns the bullets. – Rabbid76 Oct 03 '19 at 18:29
  • what does the ```+ 1``` do? – d'arby Oct 03 '19 at 18:31
  • @d'arby It adds 1 to the number which is stored in `pygame.USEREVENT`. You can use `pygame.USEREVENT+4711`, too. Use any number >= `pygame.USEREVENT` for your event id. – Rabbid76 Oct 03 '19 at 18:31
  • ahh i see. Will it affect anything in my code if it's changed? – d'arby Oct 03 '19 at 18:33
  • No, it is just an id (a value which represents a "name"). The internal name (value) of the event is the number `pygame.USEREVENT+1` – Rabbid76 Oct 03 '19 at 18:34
  • 1
    oh ok. Thanks for the help! – d'arby Oct 03 '19 at 18:35
  • 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. This would loop until the enemy is killed – d'arby Oct 03 '19 at 18:39
  • 1
    I didn't realise you could use it that way. Thanks – d'arby Oct 03 '19 at 18:53
  • ok it's been a while and I get this is an old post. But I tried doing that thing where you disable the timer by passing 0 in for the ms, but when I run the program and the boss appears, the boss just doesn't shoot at all – d'arby Aug 13 '20 at 21:58
  • @d'arby Of course, passing 0 to the timer, means to stop the timer. Anyway, if you've a new question then please [Ask a public question](https://stackoverflow.com/questions/ask). – Rabbid76 Aug 14 '20 at 06:57
  • should've worded that better. Basically I did what you did where if it's killed the timer is set to 0. But then when the boss appears on the screen (when it's alive), the boss just doesn't shoot, even though it's not in a killed state – d'arby Aug 15 '20 at 15:09