-1

I am making the game Space Invaders in Pygame and I want to let the enemy shoot randomly at the player. At this moment I can only let the enemy shoot at the player by pressing the tab button. But it should do this automatically and with a random interval. How can I get this working, without needing to press tab? Thanks.

import pygame, sys
from pygame.locals import *
import random

screenWidth = 800
screenHeight = 600
FPS = 60

pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((screenWidth,screenHeight))
pygame.display.set_caption("Space Invaders")
clock = pygame.time.Clock()

shipWidth = 67

#colors
black=(0,0,0)
blue=(0,0, 255)
green=(0,128,0)
red=(255,0,0)
white=(255,255,255)
yellow=(255,255,0)

def app_quit():
    pygame.quit()
    sys.exit("System exit.")

class Player(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("spaceship3.png").convert()
        self.image.set_colorkey(white)
        self.rect = self.image.get_rect()
        self.rect.centerx = screenWidth / 2
        self.rect.bottom = screenHeight - 10


    def update(self):
        self.speedx = 0
        if event.type == KEYDOWN and event.key == K_LEFT:
            self.speedx = -2
        elif event.type == KEYDOWN and event.key == K_RIGHT:
            self.speedx = 2
        self.rect.x += self.speedx
        if self.rect.right > screenWidth:
            self.rect.right = screenWidth
        if self.rect.left < 0:
            self.rect.left = 0

    def shootPlayer(self):
        bulletPlayer = BulletPlayer(self.rect.centerx, self.rect.top)
        allSprites.add(bulletPlayer)
        bulletsPlayer.add(bulletPlayer)

class Enemy(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("enemy.png").convert()
        self.image.set_colorkey(white)
        self.rect = self.image.get_rect()
        self.rect.x = 0
        self.rect.y = random.randrange(0, 200)
        self.speedx = random.randrange(1, 2)

    def update(self):
        self.rect.x += self.speedx
        if self.rect.right > screenWidth:
            self.rect.x = 0
            self.rect.y = random.randrange(0, 250)
            self.speedx = random.randrange(1, 3)
        # if self.rect.x > screenWidth: #kill when of the screen
        #     self.kill()

    def shootEnemy(self):
         bulletEnemy = BulletEnemy(self.rect.centerx, self.rect.bottom)
         allSprites.add(bulletEnemy)
         bulletsEnemy.add(bulletEnemy)

class BulletPlayer(pygame.sprite.Sprite):
    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("bullet.png").convert()
        self.image.set_colorkey(white)
        self.rect = self.image.get_rect()
        self.rect.bottom = y
        self.rect.centerx = x
        self.speedy = -3

    def update(self):
        self.rect.y += self.speedy
        if self.rect.bottom < 0:
            self.kill()

class BulletEnemy(pygame.sprite.Sprite):
    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("bulletenemy.png").convert()
        self.image.set_colorkey(white)
        self.rect = self.image.get_rect()
        self.rect.bottom = y
        self.rect.centerx = x
        self.speedy = 2

    def update(self):
        self.rect.y += self.speedy
        if self.rect.bottom > screenHeight:
            self.kill()

class Wall(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("wall.png").convert()
        self.rect = self.image.get_rect()
        self.rect.center = 100, 300

allSprites = pygame.sprite.Group()
player = Player()
enemy = pygame.sprite.Group()
bulletsPlayer = pygame.sprite.Group()
bulletsEnemy = pygame.sprite.Group()
wall = Wall()
allSprites.add(player, enemy, bulletsPlayer, bulletsEnemy, wall)

for i in range(1):
    e = Enemy()
    allSprites.add(e)
    enemy.add(e)

running = True
while True:

    for event in pygame.event.get():
        if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
            running = False
            app_quit()
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                player.shootPlayer()
            if event.key == pygame.K_TAB:
                random.choice(enemy.sprites()).shootEnemy()

    allSprites.update()

    hitplayer = pygame.sprite.spritecollide(player, bulletsEnemy, True)
    if hitplayer:
        running = app_quit()

    hitenemy = pygame.sprite.groupcollide(enemy, bulletsPlayer, True, True)
    if hitenemy:
        running = app_quit()

    screen.fill(black)
    allSprites.draw(screen)
    pygame.display.flip()

pygame.quit()
Rebecca Bibye
  • 190
  • 2
  • 18
bhr
  • 477
  • 1
  • 5
  • 14

2 Answers2

1

You need a random timer variable which you can decrement by the dt (delta time) each frame. When it's below zero, create a bullet instance, add it to the group and reset the timer. I use the random.uniform function here which gives you a float, but you could also use random.randrange or randint if you want ints. To get the delta time (the time since the last tick) just assign the value that clock.tick(fps) returns to a variable.

# The timer is the time in seconds until the enemy shoots.
timer = random.uniform(2, 6)  # Random float between 2 and 6.
dt = 0

running = True
while True:
    # Event handling omitted.

    # Decrease the timer by the delta time.
    timer -= dt
    if timer <= 0:  # Ready to fire.
        # Pick a random enemy to get the x and y coords.
        random_enemy = random.choice(enemy.sprites())
        enemy_x, enemy_y = random_enemy.rect.center
        # Create a bullet and add it to the sprite groups.
        bullet = BulletEnemy(enemy_x, enemy_y)
        allSprites.add(bullet)
        enemy.add(bullet)
        timer = random.uniform(2, 6)  # Reset the timer.

    # Collision detection and drawing omitted.

    # clock.tick returns the time that has passed since the last frame.
    dt = clock.tick(60) / 1000  # / 1000 to convert it to seconds.
skrx
  • 19,980
  • 5
  • 34
  • 48
1

One way to do it is to create a custom event and trigger it based off some conditions, such as time.

You can use pygame.event.Event() and pygame.event.post() to trigger an event manually instead of using the Tab key. To setup this event on time you can use pygame.time.set_timer(myEvent, time). After that your main loop just needs to check for the event with pygame.event.get().

There is a good example of how to use custom events in pygame here: PyGame Custom Event

The author's example is even a Space Invaders type game so it will be useful to look at how it is written.

zerox1212
  • 166
  • 1
  • 7