Стрелялка с Pygame №2: спрайты врагов

Вторая часть проекта «Стрелялка с Pygame». В этот раз в игре появятся враги, от которых должен будет уклоняться игрок.

В этой серии уроков будет создана полноценная игра на языке Python с помощью библиотеки Pygame. Это будет особенно интересно начинающим программистам, которые уже знакомы с основами языка и хотят углубить знания, а также узнать, что лежит в основе создания игр.

Спрайты врагов

Пока что можно не думать о том, какими именно будут спрайты врагов. Главное, чтобы они просто отображались на экране. Можно сделать проект, в котором космический корабль будет уклоняться от метеоритов, или единорог — от пицц. Это никак не затронет код, поэтому внешний вид не столь важен на данном этапе.

Учитывая это, нужно дать спрайту врага в коде какое-то общее название. Почти идеальным именем для такого рода объектов (которые двигаются в игре) является моб (вы могли слышать это выражение раньше).

Начнем с определения свойств спрайта:

class Mob(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((30, 40))
        self.image.fill(RED)
        self.rect = self.image.get_rect()
        self.rect.x = random.randrange(WIDTH - self.rect.width)
        self.rect.y = random.randrange(-100, -40)
        self.speedy = random.randrange(1, 8)

Важно определить хорошую стартовую точку для появления мобов. Не хочется, чтобы они возникали из ниоткуда, поэтому нужно просто выбрать значение, которое бы размещало объект сверху за пределами экрана (y < 0), а значение x должно быть в пределах двух сторон.

Дальше для функции обновления нужно задать движения спрайта с определенной скоростью, но что с ним будет, когда он доберется до нижней части экрана? Его можно удалить и создать новый или же можно перенести этот же спрайт в случайное место в верхней части экрана.

def update(self):
        self.rect.y += self.speedy
        if self.rect.top > HEIGHT + 10:
            self.rect.x = random.randrange(WIDTH - self.rect.width)
            self.rect.y = random.randrange(-100, -40)
            self.speedy = random.randrange(1, 8)

Появление врагов

Врагов будет много, поэтому нужно создать группу mobs для них всех. Это также упростит работу с ними в дальнейшем. После этого нужно вызвать определенное количество мобов и добавить их в группы.

player = Player()
all_sprites.add(player)
for i in range(8):
    m = Mob()
    all_sprites.add(m)
    mobs.add(m)

Должен получиться поток мобов, которые опускаются вниз по экрану:

Поток мобов, которые опускаются вниз по экрану

Пока что все отлично, но мобы, двигающиеся ровно вниз, смотрятся скучно. Нужно добавить движение по координате x:

class Mob(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((30, 40))
        self.image.fill(RED)
        self.rect = self.image.get_rect()
        self.rect.x = random.randrange(WIDTH - self.rect.width)
        self.rect.y = random.randrange(-100, -40)
        self.speedy = random.randrange(1, 8)
        self.speedx = random.randrange(-3, 3)

    def update(self):
        self.rect.x += self.speedx
        self.rect.y += self.speedy
        if self.rect.top > HEIGHT + 10 or self.rect.left < -25 or self.rect.right > WIDTH + 20:
            self.rect.x = random.randrange(WIDTH - self.rect.width)
            self.rect.y = random.randrange(-100, -40)
            self.speedy = random.randrange(1, 8)

Также нужно изменить инструкцию if, которая создает новых мобов в тот момент, когда те пропадают с экрана. Моб, который двигается по диагонали, пропадет с экрана задолго до того как доберется до нижней части, поэтому нужно перезагрузить его быстрее.

Теперь игра должна выглядеть следующим образом:

Поток мобов, которые опускаются рандомно по экрану

Код урока — shmup-2.py

В следующем уроке научимся определять, когда два моба сталкиваются и дадим игроку возможность отстреливаться.