Стрелялка с Pygame №1: спрайт игрока и управление

14727

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

Перед стартом

Если вы еще не знакомы с pygame, вернитесь и закончите первый урок в водной части «Библиотека Pygame / Часть 1. Введение». Дальше будет использоваться программа pygame template.py, которая была создана в том уроке, как основа для этого.

В этой серии мы будем работать над игрой в жанре «Shmup» или «Shoot ’em up» (или, если еще проще, «Стрелялка»). Игрок будет пилотом маленького космического корабля, который пытается выжить среди метеоритов и прочих предметов, летящих на него.

Для начала нужно сохранить файл pygame template.py с новым именем. Таким образом вы сможете использовать этот шаблон в будущем для других игр. Можно назвать файл просто как shmup.py.

В первую очередь, необходимо отредактировать настройки, добавив некоторые значения в игру:

WIDTH = 480
HEIGHT = 600
FPS = 60

Игра будет выполнена в «портретном режиме» — это значит, что высота окна больше, чем его ширина. Игра будет экшеном, поэтому важно задать высокое значение кадров в секунду. В таком случае спрайты будут двигаться максимально плавно. 60 — идеальное значение.

Спрайт игрока

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

Это начало спрайта игрока:

class Player(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((50, 40))
        self.image.fill(GREEN)
        self.rect = self.image.get_rect()
        self.rect.centerx = WIDTH / 2
        self.rect.bottom = HEIGHT - 10
        self.speedx = 0

Для игрока выбран размер 50х40 пикселей. Он будет находится по центру в нижней части экрана. Также есть свойство speedx, которое будет отслеживать, с какой скоростью двигается игрок по оси x (со стороны в сторону). Если вы не до конца понимаете, как это все работает, вернитесь к уроку «Работа со спрайтами».

Метод update() спрайта запускается в каждом кадре. Он будет перемещать спрайт с конкретной скоростью:

    def update(self):
        self.rect.x += self.speedx

Теперь нужно показать спрайт, чтобы убедиться, что он отображается на экране:

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

Не забывайте, что каждый созданный спрайт должен быть добавлен в группу all_sprites, так чтобы он обновлялся и прорисовывался на экране.

Движение/управление

Управлять в этой игре нужно будет с помощью клавиатуры, поэтому игрок должен будет двигаться при нажатии кнопок Влево или Вправо (это могут быть a или d).

Когда речь заходит об использовании кнопок в игре, есть выбор, а это значит, что речь идет о Событиях:

1 вариант: в этой очереди событий можно определить два события (по одному для каждой кнопки), каждое из которых будет менять скорость игрока, соответственно:

    for event in pygame.event.get():
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                player.speedx = -8
            if event.key == pygame.K_RIGHT:
                player.speedx = 8

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

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

def update(self):
        self.speedx = 0
        keystate = pygame.key.get_pressed()
        if keystate[pygame.K_LEFT]:
            self.speedx = -8
        if keystate[pygame.K_RIGHT]:
            self.speedx = 8
        self.rect.x += self.speedx

Этот код устанавливает скорость speedx на значении 0 для каждого кадра, а затем проверяет, не нажата ли кнопка. pygame.key.get_pressed() возвращает словарь со всеми клавишами клавиатуры и значениями True или False, которые указывают на то, нажата ли какая-то из них. Если одна из кнопок нажимается, скорость меняется соответственно.

В пределах экрана

Наконец, нужно сделать так, чтобы спрайт не пропадал с экрана. Для этого нужно добавить этот код к update() игрока:

        if self.rect.right > WIDTH:
            self.rect.right = WIDTH
        if self.rect.left < 0:
            self.rect.left = 0

Теперь если rect попробует двигаться за пределы экрана, он остановится. Второй вариант — телепортировать спрайт с одного края экрана ко второму, когда он туда доберется. Но в этой игре предпочтительнее тормозить игрока.

Итог

Вот весь код этого шага:

# Игра Shmup - 1 часть
# Cпрайт игрока и управление
import pygame
import random

WIDTH = 480
HEIGHT = 600
FPS = 60

# Задаем цвета
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)

# Создаем игру и окно
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Shmup!")
clock = pygame.time.Clock()

class Player(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((50, 40))
        self.image.fill(GREEN)
        self.rect = self.image.get_rect()
        self.rect.centerx = WIDTH / 2
        self.rect.bottom = HEIGHT - 10
        self.speedx = 0

    def update(self):
        self.speedx = 0
        keystate = pygame.key.get_pressed()
        if keystate[pygame.K_LEFT]:
            self.speedx = -8
        if keystate[pygame.K_RIGHT]:
            self.speedx = 8
        self.rect.x += self.speedx
        if self.rect.right > WIDTH:
            self.rect.right = WIDTH
        if self.rect.left < 0:
            self.rect.left = 0

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

# Цикл игры
running = True
while running:
    # Держим цикл на правильной скорости
    clock.tick(FPS)
    # Ввод процесса (события)
    for event in pygame.event.get():
        # проверка для закрытия окна
        if event.type == pygame.QUIT:
            running = False

    # Обновление
    all_sprites.update()
    
    # Рендеринг
    screen.fill(BLACK)
    all_sprites.draw(screen)
    # После отрисовки всего, переворачиваем экран
    pygame.display.flip()

pygame.quit()

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

Тест на знание python

Как узнать длину списка?
Что выведет этот код?
Что выведет этот код?
Что выведет этот код?
Что выведет этот код?
Александр
Я создал этот блог в 2018 году, чтобы распространять полезные учебные материалы, документации и уроки на русском. На сайте опубликовано множество статей по основам python и библиотекам, уроков для начинающих и примеров написания программ. Пишу на популярные темы: веб-разработка, работа с базами данных, data sciense и другие...