Alfa Brain

Создание простой игры на Python при помощи библиотеки Pygame

Алексей ВечкановАлексей Вечканов   

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

Справедливости ради, на Python нет больших игр, язык создан для других целей. Но создать простенькую, кроссплатформенную инди-игру - труда не составит.

Pygame - это библиотека для разработки игр и мультимедийных приложений на языке Python. Она была создана в 2000 году программистом из Ирландии, Питером Линдером, как ответ на отсутствие подобных инструментов для Python на тот момент.

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

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

Цель

Мы будем создавать простенькую аркадную по типу Space Invaders для двух игроков. Игроки управляют космическим кораблем и выпускают друг по другу снаряды. У каждого игрока есть некоторое количество жизней. Первый игрок потративший все жизни считается проигравшим.

Пример итоговой игры.
Пример итоговой игры.

Ссылка на репозиторий с готовой игрой, если вам вздумается сразу скачать готовый код и посмотреть результат.

Настройка окружения

Итак, приступим.

Создадим новый проект и файл main.py

Приступаем к работе с новым файлом main.py
Приступаем к работе с новым файлом main.py

Теперь нам необходимо установить библиотеку pygame в наш проект. Воспользуемся пакетным менеджером pip (он устанавливается вместе с Python)

Откройте терминал для ввода команды установки. Если вы используете VS Code вы можете открыть терминал в текущей папке при помощи кнопок на панели инструментов.

Открываем терминал для ввода команд
Открываем терминал для ввода команд

Вводим команду: pip install pygame

Пакетный менеджер pip устанавливает необходимые модули pygame
Пакетный менеджер pip устанавливает необходимые модули pygame

Отлично. Можем начинать создание игры.

Создания окна игры

Перепишите следующий код в файл main.py

Я буду помечать код комментариями, чтобы вам было понятно что происходит на каждой строчке.

1# Подключаем игровой движок Pygame
2import pygame
3
4# Подготавливаем необходимые модули Pygame
5pygame.init()
6
7### Константы ###
8# Константы размера окна
9WIDTH = 600
10HEIGHT = 300
11
12# Задаем размеры игрового окна
13screen = pygame.display.set_mode((WIDTH, HEIGHT))
14
15# Запускаем бесконечный цикл программы
16# Это делается чтобы программа не завершалась и постоянно рисовала новые кадры игры
17while True:
18    pygame.display.update()

Запустите программу. Вы должны увидеть окно черного цвета с разрешением 600 на 300 пикселей.

Обратите внимание, что кнопки свернуть, и закрыть программу неактивны.

Кнопки в заголовке программы не активны
Кнопки в заголовке программы не активны

Давайте добавим возможность свернуть и закрыть игру при помощи стандартных кнопок.

Для этого в бесконечный цикл добавьте следующий код:

1# Запускаем бесконечный цикл программы
2# Это делается чтобы программа не завершалась и постоянно рисовала новые кадры игры
3while True:
4    # Постоянно проверяем события игры и если присутствует событие Выход - останавливаем игру.
5    for event in pygame.event.get():
6        if event.type == pygame.QUIT:
7            pygame.quit()
8
9    # Обновляем кадры игры
10    pygame.display.update()

В бесконечном цикле мы проверяем, не случилось ли события QUIT (выход), в процессе работы программы и если пользователь нажал на выход, значит мы зарегистрировали событие QUIT - закрываем игру при помощи команды pygame.quit()

Рисуем задний фон

Теперь давайте нарисуем задник нашей игры. Сохраните картинку и положите ее в директорию assets (предварительно создав ее) в корне директории вашей игры.

Задний фон игры.
Задний фон игры.
Директория assets в корне проекта игры.
Директория assets в корне проекта игры.

Так же нам понадобится модуль os. Модуль os позволяет работать с файловой системой компьютера, а именно, поможет нам загрузить картинку.

Загрузим картинку в память при помощи следующего кода:

1# Подключаем модуль для работы с файловой системой
2import os
3
4# Загружаем изображение в память
5SPACE_IMAGE = pygame.image.load(os.path.join('./assets', 'space.jpg'))
6
7# Создаем объект фона с разрешением окна
8SPACE_BG = pygame.transform.scale(SPACE_IMAGE, (WIDTH, HEIGHT))

И теперь достаточно поместить вызов screen.blit(SPACE, (0, 0)) внутрь нашего бесконечного цикла рисующего карды и фон будет виден игроку. Метод blit позволяет наложить одно изображение на другое. В нашем случае нам нужно наложит изображение поверх окна  screen.

1# Запускаем бесконечный цикл программы
2# Это делается чтобы программа не завершалась и постоянно рисовала новые кадры игры
3while True:
4    # Рисуем изображение на заднем фоне
5    screen.blit(SPACE_BG, (0, 0))

Промежуточный результат #1

Работает:

- Кнопка закрыть/свернуть

- Отображается задний фон

1# Подключаем игровой движок Pygame
2import pygame
3# Подключаем модуль для работы с файловой системой
4import os
5
6# Подготавливаем необходимые модули Pygame
7pygame.init()
8
9### Константы ###
10# Константы размера окна
11WIDTH = 600
12HEIGHT = 300
13
14# Задаем размеры игрового окна
15screen = pygame.display.set_mode((WIDTH, HEIGHT))
16
17# Загружаем изображение в память
18SPACE_IMAGE = pygame.image.load(os.path.join('./assets', 'space.jpg'))
19
20# Создаем объект фона с разрешением окна
21SPACE_BG = pygame.transform.scale(SPACE_IMAGE, (WIDTH, HEIGHT))
22
23# Запускаем бесконечный цикл программы
24# Это делается чтобы программа не завершалась и постоянно рисовала новые кадры игры
25while True:
26    # Рисуем изображение на заднем фоне
27    screen.blit(SPACE_BG, (0, 0))
28
29    # Постоянно проверяем события игры и если присутствует событие Выход - останавливаем игру.
30    for event in pygame.event.get():
31        if event.type == pygame.QUIT:
32            pygame.quit()
33
34    # Обновляем кадры игры
35    pygame.display.update()

Разделитель игрового экрана

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

Создадим объект прямоугольник.

1# Формируем объект границы
2BORDER = pygame.Rect(WIDTH//2 - 5, 0, 10, HEIGHT)
3

Обратите внимание, первые два аргумента функции это x и y расположения прямоугольника, а третий и четвертый аргументы это ширина и высота прямоугольника. Ширина прямоугольника 10, а высота такая же как высота экрана игры. По y прямоугольник начинается от верхнего края экрана, а вот по x мы берем ширину экрана, делим ее на 2 и отнимаем 5 (половину ширины прямоугольника). Благодаря этому прямоугольник располагается прямо посередине экрана игры. Осталось только отрисовать этот объект. Добавим отрисовку в бесконечный цикл, рядом с отрисовкой фона.

1# Рисуем прямоугольник 
2pygame.draw.rect(screen, "white", BORDER)

Метод rect объекта draw позволяет отрисовать прямоугольник. Первый аргумент screeen указывает где нужно отрисовать, второй аргумент задает цвет, третий аргумент задает сам объект рисования, наш BORDER.

Должно получиться вот так:

Рисуем разделитель экрана для игроков.
Рисуем разделитель экрана для игроков.

Промежуточный результат #2

Работает:

- Кнопка закрыть/свернуть

- Отображается задний фон

- Разделитель экрана

1# Подключаем игровой движок Pygame
2import pygame
3# Подключаем модуль для работы с файловой системой
4import os
5
6# Подготавливаем необходимые модули Pygame
7pygame.init()
8
9### Константы ###
10# Константы размера окна
11WIDTH = 600
12HEIGHT = 300
13
14# Задаем размеры игрового окна
15screen = pygame.display.set_mode((WIDTH, HEIGHT))
16
17# Загружаем изображение в память
18SPACE_IMAGE = pygame.image.load(os.path.join('./assets', 'space.jpg'))
19
20# Создаем объект фона с разрешением окна
21SPACE_BG = pygame.transform.scale(SPACE_IMAGE, (WIDTH, HEIGHT))
22
23# Формируем объект границы
24BORDER = pygame.Rect(WIDTH//2 - 2, 0, 4, HEIGHT)
25
26# Запускаем бесконечный цикл программы
27# Это делается чтобы программа не завершалась и постоянно рисовала новые кадры игры
28while True:
29    # Рисуем изображение на заднем фоне
30    screen.blit(SPACE_BG, (0, 0))
31
32    # Рисуем прямоугольник 
33    pygame.draw.rect(screen, "white", BORDER)
34
35    # Постоянно проверяем события игры и если присутствует событие Выход - останавливаем игру.
36    for event in pygame.event.get():
37        if event.type == pygame.QUIT:
38            pygame.quit()
39
40    # Обновляем кадры игры
41    pygame.display.update()

Создаем игрока

Давайте нарисуем игроков и зададим им движение.

Ниже представлены две картинки: Красный космический корабль и Желтый космический корабль.

Скопируйте эти изображения в директорию assets вашего проекта под именами: spaceship_red.png и spaceship_yellow.png

Красный корабль.
Красный корабль.
Желтый корабль.
Желтый корабль.

Создадим две переменных, ширину и высоту кораблей. Добавьте их к блоку константы.

1# Размеры корабля
2SPACESHIP_WIDTH = 55
3SPACESHIP_HEIGHT = 40

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

1# Загружаем изображение красного корабля 
2RED_SPACESHIP_IMAGE = pygame.image.load(
3    os.path.join('./assets', 'spaceship_red.png'))
4# Разворачиваем изображение в нужном направлении
5RED_SPACESHIP = pygame.transform.rotate(pygame.transform.scale(
6    RED_SPACESHIP_IMAGE, (SPACESHIP_WIDTH, SPACESHIP_HEIGHT)), 90)
7
8# Загружаем изображение желтого корабля 
9YELLOW_SPACESHIP_IMAGE = pygame.image.load(
10    os.path.join('./assets', 'spaceship_yellow.png'))
11# Разворачиваем изображение в нужном направлении
12YELLOW_SPACESHIP = pygame.transform.rotate(pygame.transform.scale(
13    YELLOW_SPACESHIP_IMAGE, (SPACESHIP_WIDTH, SPACESHIP_HEIGHT)), 270)

Картинки загрузили, теперь нужно создать два объекта прямоугольника для будущих кораблей. Так как объекты Rect хранят ширину, высоту, и координаты x и y - это идеальные кандидаты для хранения данных кораблей.

1# Создаем два объекта/прямоугольника
2red = pygame.Rect(100, 150, SPACESHIP_WIDTH, SPACESHIP_HEIGHT)
3yellow = pygame.Rect(500, 150, SPACESHIP_WIDTH, SPACESHIP_HEIGHT)

Отлично, осталось только отрисовать наши корабли на экране. Добавьте следующий код в бесконечный цикл отрисовки экрана.

1# Рисуем корабли
2screen.blit(YELLOW_SPACESHIP, (yellow.x, yellow.y))
3screen.blit(RED_SPACESHIP, (red.x, red.y))

Промежуточный результат #3

Работает:

- Кнопка закрыть/свернуть

- Отображается задний фон

- Разделитель экрана

- Отрисовка игроков

1# Подключаем игровой движок Pygame
2import pygame
3# Подключаем модуль для работы с файловой системой
4import os
5
6# Подготавливаем необходимые модули Pygame
7pygame.init()
8
9### Константы ###
10# Константы размера окна
11WIDTH = 600
12HEIGHT = 300
13# Размеры корабля
14SPACESHIP_WIDTH = 55
15SPACESHIP_HEIGHT = 40
16
17# Задаем размеры игрового окна
18screen = pygame.display.set_mode((WIDTH, HEIGHT))
19
20# Загружаем изображение в память
21SPACE_IMAGE = pygame.image.load(os.path.join('./assets', 'space.jpg'))
22
23# Создаем объект фона с разрешением окна
24SPACE_BG = pygame.transform.scale(SPACE_IMAGE, (WIDTH, HEIGHT))
25
26# Формируем объект границы
27BORDER = pygame.Rect(WIDTH//2 - 2, 0, 4, HEIGHT)
28
29# Загружаем изображение красного корабля 
30RED_SPACESHIP_IMAGE = pygame.image.load(
31    os.path.join('./assets', 'spaceship_red.png'))
32# Разворачиваем изображение в нужном направлении
33RED_SPACESHIP = pygame.transform.rotate(pygame.transform.scale(
34    RED_SPACESHIP_IMAGE, (SPACESHIP_WIDTH, SPACESHIP_HEIGHT)), 90)
35
36# Загружаем изображение желтого корабля 
37YELLOW_SPACESHIP_IMAGE = pygame.image.load(
38    os.path.join('./assets', 'spaceship_yellow.png'))
39# Разворачиваем изображение в нужном направлении
40YELLOW_SPACESHIP = pygame.transform.rotate(pygame.transform.scale(
41    YELLOW_SPACESHIP_IMAGE, (SPACESHIP_WIDTH, SPACESHIP_HEIGHT)), 270)
42
43# Создаем два объекта/прямоугольника
44red = pygame.Rect(100, 150, SPACESHIP_WIDTH, SPACESHIP_HEIGHT)
45yellow = pygame.Rect(500, 150, SPACESHIP_WIDTH, SPACESHIP_HEIGHT)
46
47# Запускаем бесконечный цикл программы
48# Это делается чтобы программа не завершалась и постоянно рисовала новые кадры игры
49while True:
50    # Рисуем изображение на заднем фоне
51    screen.blit(SPACE_BG, (0, 0))
52
53    # Рисуем прямоугольник 
54    pygame.draw.rect(screen, "white", BORDER)
55
56    # Рисуем корабли
57    screen.blit(YELLOW_SPACESHIP, (yellow.x, yellow.y))
58    screen.blit(RED_SPACESHIP, (red.x, red.y))
59
60    # Постоянно проверяем события игры и если присутствует событие Выход - останавливаем игру.
61    for event in pygame.event.get():
62        if event.type == pygame.QUIT:
63            pygame.quit()
64
65    # Обновляем кадры игры
66    pygame.display.update()

Движение игроков

Теперь оживим наши корабли.

К блоку констант добавьте новую переменную VELOCITY. Данная переменная, как можно предположить из названия, задает скорость кораблей.

1# Скорость корабля
2VELOCITY = 1

Теперь напишем функцию движения красного корабля.

1# Функция движения красного корабля
2def red_handle_movement(keys_pressed, red):
3    # Движение ВЛЕВО
4    if keys_pressed[pygame.K_a] and red.x - VELOCITY > 0:
5        red.x -= VELOCITY
6    # Движение ВПРАВО (запрещаем двигаться вправо дальше чем граница игроков)
7    if keys_pressed[pygame.K_d] and red.x + VELOCITY + red.width < BORDER.x:
8        red.x += VELOCITY
9    # Движение ВВЕРХ (запрещаем подниматься выше 0 по координате y)
10    if keys_pressed[pygame.K_w] and red.y - VELOCITY > 0:
11        red.y -= VELOCITY
12    # Движение ВНИЗ (запрещаем опускаться ниже чем высота экрана за вычетом высоты корабля и дополнительных 15 для отступа)
13    if keys_pressed[pygame.K_s] and red.y + VELOCITY + red.height < HEIGHT - 15:
14        red.y += VELOCITY

Первым аргументом функция получает специальный объект справочник нажатых клавишей. Вторым аргументом функция получает объект Rect красного корабля.

Теперь добавим функцию для желтого корабля:

1# Функция движения желтого корабля
2def yellow_handle_movement(keys_pressed, yellow):
3    # Движение ВЛЕВО (запрещаем пересекать границу игроков)
4    if keys_pressed[pygame.K_LEFT] and yellow.x - VELOCITY > BORDER.x + BORDER.width:
5        yellow.x -= VELOCITY
6    # Движение ВПРАВО
7    if keys_pressed[pygame.K_RIGHT] and yellow.x + VELOCITY + yellow.width < WIDTH:
8        yellow.x += VELOCITY
9    # Движение ВВЕРХ
10    if keys_pressed[pygame.K_UP] and yellow.y - VELOCITY > 0:
11        yellow.y -= VELOCITY
12    # Движение ВНИЗ
13    if keys_pressed[pygame.K_DOWN] and yellow.y + VELOCITY + yellow.height < HEIGHT - 15:
14        yellow.y += VELOCITY

В данных функциях мы проверяем нажатую клавишу (Для красного игрока мы проверяем английские клавиши WASD, для желтого игрока клавиши стрелки), и в зависимости от нажатой клавиши, изменяем нужную координату объекта на скорость корабля (VELOCITY).

Отлично, осталось вызвать эти функции в цикле. Добавьте в бесконечный цикл отрисовки следующие строчки:

1# Узнаем нажатие клавишей
2  keys_pressed = pygame.key.get_pressed()
3  # Выполняем установку координат кораблей
4  red_handle_movement(keys_pressed, red)
5  yellow_handle_movement(keys_pressed, yellow)

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

Запустите программу, должно получиться вот так:

Движение красного и желтого.
Движение красного и желтого.

Промежуточный результат #4

Работает:

- Кнопка закрыть/свернуть

- Отображается задний фон

- Разделитель экрана

- Отрисовка игроков

- Движение игроков

1# Подключаем игровой движок Pygame
2import pygame
3# Подключаем модуль для работы с файловой системой
4import os
5
6# Подготавливаем необходимые модули Pygame
7pygame.init()
8
9### Константы ###
10# Константы размера окна
11WIDTH = 600
12HEIGHT = 300
13# Размеры корабля
14SPACESHIP_WIDTH = 55
15SPACESHIP_HEIGHT = 40
16# Скорость корабля
17VELOCITY = 1
18
19# Задаем размеры игрового окна
20screen = pygame.display.set_mode((WIDTH, HEIGHT))
21
22# Загружаем изображение в память
23SPACE_IMAGE = pygame.image.load(os.path.join('./assets', 'space.jpg'))
24
25# Создаем объект фона с разрешением окна
26SPACE_BG = pygame.transform.scale(SPACE_IMAGE, (WIDTH, HEIGHT))
27
28# Формируем объект границы
29BORDER = pygame.Rect(WIDTH//2 - 2, 0, 4, HEIGHT)
30
31# Загружаем изображение красного корабля 
32RED_SPACESHIP_IMAGE = pygame.image.load(
33    os.path.join('./assets', 'spaceship_red.png'))
34# Разворачиваем изображение в нужном направлении
35RED_SPACESHIP = pygame.transform.rotate(pygame.transform.scale(
36    RED_SPACESHIP_IMAGE, (SPACESHIP_WIDTH, SPACESHIP_HEIGHT)), 90)
37
38# Загружаем изображение желтого корабля 
39YELLOW_SPACESHIP_IMAGE = pygame.image.load(
40    os.path.join('./assets', 'spaceship_yellow.png'))
41# Разворачиваем изображение в нужном направлении
42YELLOW_SPACESHIP = pygame.transform.rotate(pygame.transform.scale(
43    YELLOW_SPACESHIP_IMAGE, (SPACESHIP_WIDTH, SPACESHIP_HEIGHT)), 270)
44
45# Создаем два объекта/прямоугольника
46red = pygame.Rect(100, 150, SPACESHIP_WIDTH, SPACESHIP_HEIGHT)
47yellow = pygame.Rect(500, 150, SPACESHIP_WIDTH, SPACESHIP_HEIGHT)
48
49# Функция движения красного корабля
50def red_handle_movement(keys_pressed, red):
51    # Движение ВЛЕВО
52    if keys_pressed[pygame.K_a] and red.x - VELOCITY > 0:
53        red.x -= VELOCITY
54    # Движение ВПРАВО (запрещаем пересекать границу игроков)
55    if keys_pressed[pygame.K_d] and red.x + VELOCITY + red.width < BORDER.x:
56        red.x += VELOCITY
57    # Движение ВВЕРХ (запрещаем подниматься выше 0 по координате y)
58    if keys_pressed[pygame.K_w] and red.y - VELOCITY > 0:
59        red.y -= VELOCITY
60    # Движение ВНИЗ (запрещаем опускаться ниже чем высота экрана за вычетом высоты корабля и дополнительных 15 для отступа)
61    if keys_pressed[pygame.K_s] and red.y + VELOCITY + red.height < HEIGHT - 15:
62        red.y += VELOCITY
63
64# Функция движения желтого корабля
65def yellow_handle_movement(keys_pressed, yellow):
66    # Движение ВЛЕВО (запрещаем пересекать границу игроков)
67    if keys_pressed[pygame.K_LEFT] and yellow.x - VELOCITY > BORDER.x + BORDER.width:
68        yellow.x -= VELOCITY
69    # Движение ВПРАВО
70    if keys_pressed[pygame.K_RIGHT] and yellow.x + VELOCITY + yellow.width < WIDTH:
71        yellow.x += VELOCITY
72    # Движение ВВЕРХ
73    if keys_pressed[pygame.K_UP] and yellow.y - VELOCITY > 0:
74        yellow.y -= VELOCITY
75    # Движение ВНИЗ
76    if keys_pressed[pygame.K_DOWN] and yellow.y + VELOCITY + yellow.height < HEIGHT - 15:
77        yellow.y += VELOCITY
78
79
80# Запускаем бесконечный цикл программы
81# Это делается чтобы программа не завершалась и постоянно рисовала новые кадры игры
82while True:
83    # Рисуем изображение на заднем фоне
84    screen.blit(SPACE_BG, (0, 0))
85
86    # Рисуем прямоугольник 
87    pygame.draw.rect(screen, "white", BORDER)
88
89    # Рисуем корабли
90    screen.blit(YELLOW_SPACESHIP, (yellow.x, yellow.y))
91    screen.blit(RED_SPACESHIP, (red.x, red.y))
92
93    # Постоянно проверяем события игры и если присутствует событие Выход - останавливаем игру.
94    for event in pygame.event.get():
95        if event.type == pygame.QUIT:
96            pygame.quit()
97
98    # Узнаем нажатие клавишей
99    keys_pressed = pygame.key.get_pressed()
100    # Выполняем установку координат кораблей
101    red_handle_movement(keys_pressed, red)
102    yellow_handle_movement(keys_pressed, yellow)
103
104    # Обновляем кадры игры
105    pygame.display.update()

Ограничитель кадров

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

Добавьте константу - количество кадров в секунду (frame per second):

1# Количество кадров в секунду
2FPS = 60

Затем создайте специальный объект ограничитель кадров.

1# Ограничитель кадров
2clock = pygame.time.Clock()

И теперь добавьте строчку clock.tick(FPS) сразу после вызова цикла:

1# Запускаем бесконечный цикл программы
2# Это делается чтобы программа не завершалась и постоянно рисовала новые кадры игры
3while True:
4    # Ограничиваем количество кадров игры
5    clock.tick(FPS)

Благодаря этому коду, цикл будет вызываться не чаще чем 60 раз в секунду. Это то, что нам нужно. Сохраните, запустите, проверьте.

Но теперь корабли движутся очень медленно. Все верно, ведь мы так сильно сократили количество проверок нажатых клавиш. Поправить это просто - поднимите значение VELOCITY. Я подниму до 5.

Промежуточный результат #5

Работает:

- Кнопка закрыть/свернуть

- Отображается задний фон

- Разделитель экрана

- Отрисовка игроков

- Движение игроков

- Ограничитель кадров

1# Подключаем игровой движок Pygame
2import pygame
3# Подключаем модуль для работы с файловой системой
4import os
5
6# Подготавливаем необходимые модули Pygame
7pygame.init()
8
9### Константы ###
10# Константы размера окна
11WIDTH = 600
12HEIGHT = 300
13# Размеры корабля
14SPACESHIP_WIDTH = 55
15SPACESHIP_HEIGHT = 40
16# Скорость корабля
17VELOCITY = 5
18# Количество кадров в секунду
19FPS = 60
20
21# Ограничитель кадров
22clock = pygame.time.Clock()
23
24# Задаем размеры игрового окна
25screen = pygame.display.set_mode((WIDTH, HEIGHT))
26
27# Загружаем изображение в память
28SPACE_IMAGE = pygame.image.load(os.path.join('./assets', 'space.jpg'))
29
30# Создаем объект фона с разрешением окна
31SPACE_BG = pygame.transform.scale(SPACE_IMAGE, (WIDTH, HEIGHT))
32
33# Формируем объект границы
34BORDER = pygame.Rect(WIDTH//2 - 2, 0, 4, HEIGHT)
35
36# Загружаем изображение красного корабля 
37RED_SPACESHIP_IMAGE = pygame.image.load(
38    os.path.join('./assets', 'spaceship_red.png'))
39# Разворачиваем изображение в нужном направлении
40RED_SPACESHIP = pygame.transform.rotate(pygame.transform.scale(
41    RED_SPACESHIP_IMAGE, (SPACESHIP_WIDTH, SPACESHIP_HEIGHT)), 90)
42
43# Загружаем изображение желтого корабля 
44YELLOW_SPACESHIP_IMAGE = pygame.image.load(
45    os.path.join('./assets', 'spaceship_yellow.png'))
46# Разворачиваем изображение в нужном направлении
47YELLOW_SPACESHIP = pygame.transform.rotate(pygame.transform.scale(
48    YELLOW_SPACESHIP_IMAGE, (SPACESHIP_WIDTH, SPACESHIP_HEIGHT)), 270)
49
50# Создаем два объекта/прямоугольника
51red = pygame.Rect(100, 150, SPACESHIP_WIDTH, SPACESHIP_HEIGHT)
52yellow = pygame.Rect(500, 150, SPACESHIP_WIDTH, SPACESHIP_HEIGHT)
53
54# Функция движения красного корабля
55def red_handle_movement(keys_pressed, red):
56    # Движение ВЛЕВО
57    if keys_pressed[pygame.K_a] and red.x - VELOCITY > 0:
58        red.x -= VELOCITY
59    # Движение ВПРАВО (запрещаем пересекать границу игроков)
60    if keys_pressed[pygame.K_d] and red.x + VELOCITY + red.width < BORDER.x:
61        red.x += VELOCITY
62    # Движение ВВЕРХ (запрещаем подниматься выше 0 по координате y)
63    if keys_pressed[pygame.K_w] and red.y - VELOCITY > 0:
64        red.y -= VELOCITY
65    # Движение ВНИЗ (запрещаем опускаться ниже чем высота экрана за вычетом высоты корабля и дополнительных 15 для отступа)
66    if keys_pressed[pygame.K_s] and red.y + VELOCITY + red.height < HEIGHT - 15:
67        red.y += VELOCITY
68
69# Функция движения желтого корабля
70def yellow_handle_movement(keys_pressed, yellow):
71    # Движение ВЛЕВО (запрещаем пересекать границу игроков)
72    if keys_pressed[pygame.K_LEFT] and yellow.x - VELOCITY > BORDER.x + BORDER.width:
73        yellow.x -= VELOCITY
74    # Движение ВПРАВО
75    if keys_pressed[pygame.K_RIGHT] and yellow.x + VELOCITY + yellow.width < WIDTH:
76        yellow.x += VELOCITY
77    # Движение ВВЕРХ
78    if keys_pressed[pygame.K_UP] and yellow.y - VELOCITY > 0:
79        yellow.y -= VELOCITY
80    # Движение ВНИЗ
81    if keys_pressed[pygame.K_DOWN] and yellow.y + VELOCITY + yellow.height < HEIGHT - 15:
82        yellow.y += VELOCITY
83
84
85# Запускаем бесконечный цикл программы
86# Это делается чтобы программа не завершалась и постоянно рисовала новые кадры игры
87while True:
88    # Ограничиваем количество кадров игры
89    clock.tick(FPS)
90
91    # Рисуем изображение на заднем фоне
92    screen.blit(SPACE_BG, (0, 0))
93
94    # Рисуем прямоугольник 
95    pygame.draw.rect(screen, "white", BORDER)
96
97    # Рисуем корабли
98    screen.blit(YELLOW_SPACESHIP, (yellow.x, yellow.y))
99    screen.blit(RED_SPACESHIP, (red.x, red.y))
100
101    # Постоянно проверяем события игры и если присутствует событие Выход - останавливаем игру.
102    for event in pygame.event.get():
103        if event.type == pygame.QUIT:
104            pygame.quit()
105
106    # Узнаем нажатие клавишей
107    keys_pressed = pygame.key.get_pressed()
108    # Выполняем установку координат кораблей
109    red_handle_movement(keys_pressed, red)
110    yellow_handle_movement(keys_pressed, yellow)
111
112    # Обновляем кадры игры
113    pygame.display.update()
114
115

Здоровье игроков

Теперь добавим отображение здоровья игроков.

Создайте две переменные для хранения здоровья игроков:

1# Здоровье игроков
2red_health = 10
3yellow_health = 10

Так же к константам добавьте переменную шрифта:

1# Шрифт здоровья
2HEALTH_FONT = pygame.font.SysFont('comicsans', 20)

Отлично. Теперь в бесконечном цикле отрисовки нарисуем текст:

1# Отображаем здоровье на экране
2red_health_text = HEALTH_FONT.render(
3    "Health: " + str(red_health), 1, "white")
4yellow_health_text = HEALTH_FONT.render(
5    "Health: " + str(yellow_health), 1, "white")
6screen.blit(red_health_text, (10, 10))
7screen.blit(yellow_health_text, (WIDTH - red_health_text.get_width() - 10, 10))

Обратите внимание, что рисовать текст здоровья нужно последним, иначе если сначала отрисовать текст, а затем задний фон, то последний просто перекроет текст.

Должно получиться так:

Отображение здоровья игроков.
Отображение здоровья игроков.

Промежуточный результат #6

Работает:

- Кнопка закрыть/свернуть

- Отображается задний фон

- Разделитель экрана

- Отрисовка игроков

- Движение игроков

- Ограничитель кадров

- Здоровье игроков

1# Подключаем игровой движок Pygame
2import pygame
3# Подключаем модуль для работы с файловой системой
4import os
5
6# Подготавливаем необходимые модули Pygame
7pygame.init()
8
9### Константы ###
10# Константы размера окна
11WIDTH = 600
12HEIGHT = 300
13# Размеры корабля
14SPACESHIP_WIDTH = 55
15SPACESHIP_HEIGHT = 40
16# Скорость корабля
17VELOCITY = 5
18# Количество кадров в секунду
19FPS = 60
20# Шрифт здоровья
21HEALTH_FONT = pygame.font.SysFont('comicsans', 20)
22
23# Ограничитель кадров
24clock = pygame.time.Clock()
25
26# Задаем размеры игрового окна
27screen = pygame.display.set_mode((WIDTH, HEIGHT))
28
29# Загружаем изображение в память
30SPACE_IMAGE = pygame.image.load(os.path.join('./assets', 'space.jpg'))
31
32# Создаем объект фона с разрешением окна
33SPACE_BG = pygame.transform.scale(SPACE_IMAGE, (WIDTH, HEIGHT))
34
35# Формируем объект границы
36BORDER = pygame.Rect(WIDTH//2 - 2, 0, 4, HEIGHT)
37
38# Загружаем изображение красного корабля 
39RED_SPACESHIP_IMAGE = pygame.image.load(
40    os.path.join('./assets', 'spaceship_red.png'))
41# Разворачиваем изображение в нужном направлении
42RED_SPACESHIP = pygame.transform.rotate(pygame.transform.scale(
43    RED_SPACESHIP_IMAGE, (SPACESHIP_WIDTH, SPACESHIP_HEIGHT)), 90)
44
45# Загружаем изображение желтого корабля 
46YELLOW_SPACESHIP_IMAGE = pygame.image.load(
47    os.path.join('./assets', 'spaceship_yellow.png'))
48# Разворачиваем изображение в нужном направлении
49YELLOW_SPACESHIP = pygame.transform.rotate(pygame.transform.scale(
50    YELLOW_SPACESHIP_IMAGE, (SPACESHIP_WIDTH, SPACESHIP_HEIGHT)), 270)
51
52# Создаем два объекта/прямоугольника
53red = pygame.Rect(100, 150, SPACESHIP_WIDTH, SPACESHIP_HEIGHT)
54yellow = pygame.Rect(500, 150, SPACESHIP_WIDTH, SPACESHIP_HEIGHT)
55
56# Здоровье игроков
57red_health = 10
58yellow_health = 10
59
60# Функция движения красного корабля
61def red_handle_movement(keys_pressed, red):
62    # Движение ВЛЕВО
63    if keys_pressed[pygame.K_a] and red.x - VELOCITY > 0:
64        red.x -= VELOCITY
65    # Движение ВПРАВО (запрещаем пересекать границу игроков)
66    if keys_pressed[pygame.K_d] and red.x + VELOCITY + red.width < BORDER.x:
67        red.x += VELOCITY
68    # Движение ВВЕРХ (запрещаем подниматься выше 0 по координате y)
69    if keys_pressed[pygame.K_w] and red.y - VELOCITY > 0:
70        red.y -= VELOCITY
71    # Движение ВНИЗ (запрещаем опускаться ниже чем высота экрана за вычетом высоты корабля и дополнительных 15 для отступа)
72    if keys_pressed[pygame.K_s] and red.y + VELOCITY + red.height < HEIGHT - 15:
73        red.y += VELOCITY
74
75# Функция движения желтого корабля
76def yellow_handle_movement(keys_pressed, yellow):
77    # Движение ВЛЕВО (запрещаем пересекать границу игроков)
78    if keys_pressed[pygame.K_LEFT] and yellow.x - VELOCITY > BORDER.x + BORDER.width:
79        yellow.x -= VELOCITY
80    # Движение ВПРАВО
81    if keys_pressed[pygame.K_RIGHT] and yellow.x + VELOCITY + yellow.width < WIDTH:
82        yellow.x += VELOCITY
83    # Движение ВВЕРХ
84    if keys_pressed[pygame.K_UP] and yellow.y - VELOCITY > 0:
85        yellow.y -= VELOCITY
86    # Движение ВНИЗ
87    if keys_pressed[pygame.K_DOWN] and yellow.y + VELOCITY + yellow.height < HEIGHT - 15:
88        yellow.y += VELOCITY
89
90
91# Запускаем бесконечный цикл программы
92# Это делается чтобы программа не завершалась и постоянно рисовала новые кадры игры
93while True:
94    # Ограничиваем количество кадров игры
95    clock.tick(FPS)
96
97    # Рисуем изображение на заднем фоне
98    screen.blit(SPACE_BG, (0, 0))
99
100    # Рисуем прямоугольник 
101    pygame.draw.rect(screen, "white", BORDER)
102
103    # Рисуем корабли
104    screen.blit(YELLOW_SPACESHIP, (yellow.x, yellow.y))
105    screen.blit(RED_SPACESHIP, (red.x, red.y))
106
107    # Отображаем здоровье на экране
108    red_health_text = HEALTH_FONT.render(
109        "Health: " + str(red_health), 1, "white")
110    yellow_health_text = HEALTH_FONT.render(
111        "Health: " + str(yellow_health), 1, "white")
112    screen.blit(red_health_text, (10, 10))
113    screen.blit(yellow_health_text, (WIDTH - red_health_text.get_width() - 10, 10))
114
115    # Постоянно проверяем события игры и если присутствует событие Выход - останавливаем игру.
116    for event in pygame.event.get():
117        if event.type == pygame.QUIT:
118            pygame.quit()
119
120    # Узнаем нажатие клавишей
121    keys_pressed = pygame.key.get_pressed()
122    # Выполняем установку координат кораблей
123    red_handle_movement(keys_pressed, red)
124    yellow_handle_movement(keys_pressed, yellow)
125
126    # Обновляем кадры игры
127    pygame.display.update()

Выстрелы

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

Создайте переменные для хранения выпущенных пуль, переменную для максимального количества выпущенных пуль, а так же переменную - скорость пули:

1# Хранение выпущенных пуль
2red_bullets = []
3yellow_bullets = []
4# Макс. выпущенных пуль
5MAX_BULLETS = 3
6# Скорость пули
7BULLET_VEL = 7

Так же создайте два новых пользовательских события - попадание в красного и попадание в желтого:

1# Пользовательские события попаданий
2YELLOW_HIT = pygame.USEREVENT + 1
3RED_HIT = pygame.USEREVENT + 2

Плюс один и плюс два просто позволяют создать новые коды событий, нам они понадобятся ниже.

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

1# Постоянно проверяем события игры и если присутствует событие Выход - останавливаем игру.
2for event in pygame.event.get():
3    if event.type == pygame.QUIT:
4        pygame.quit()
5
6    # Если произошло событие нажатия клавиши
7        if event.type == pygame.KEYDOWN:
8            # И нажали клавишу Пробел, а так же если длина листа выпущенных пуль красного меньше минимального
9            if event.key == pygame.K_SPACE and len(red_bullets) < MAX_BULLETS:
10                # Создаем объект прямоугольника для Пули
11                bullet = pygame.Rect(
12                    red.x + red.width, red.y + red.height//2 - 2, 10, 5)
13                # Добавляем выпущенную пулю красному
14                red_bullets.append(bullet)
15
16            # Если нажали клавишу Enter, создаем выпущенную пулю желтому игроку
17            if event.key == pygame.K_RETURN and len(yellow_bullets) < MAX_BULLETS:
18                # Создаем объект прямоугольника для Пули
19                bullet = pygame.Rect(
20                    yellow.x, yellow.y + yellow.height//2 - 2, 10, 5)
21                # Добавляем выпущенную пулю желтому
22                yellow_bullets.append(bullet)

Благодаря этому коду, мы программно выпускаем пули у игроков и сохраняем выпущенные пули в соответствующих списках.

Теперь нужно обработать попадания и вылет пуль за экран.

Напишите следующую функцию:

1# Обработка выпущенных пуль
2def handle_bullets(yellow_bullets, red_bullets, yellow, red):
3    # Перебираем все пули красного
4    for bullet in red_bullets:
5        # Двигаем пулю вправо
6        bullet.x += BULLET_VEL
7        # Если пуля задевает желтого игрока
8        if yellow.colliderect(bullet):
9            # Вызываем пользовательское событие попадание в Желтого
10            pygame.event.post(pygame.event.Event(YELLOW_HIT))
11            # Удаляем текущую пулю
12            red_bullets.remove(bullet)
13        # Удаляем пулю если она вышла за экран
14        elif bullet.x > WIDTH:
15            red_bullets.remove(bullet)
16
17    # Перебираем все пули желтого
18    for bullet in yellow_bullets:
19        # Двигаем пулю влево
20        bullet.x -= BULLET_VEL
21        # Если пуля задевает красного игрока
22        if red.colliderect(bullet):
23            # Вызываем пользовательское событие попадание в Красного
24            pygame.event.post(pygame.event.Event(RED_HIT))
25            # Удаляем текущую пулю
26            yellow_bullets.remove(bullet)
27        # Удаляем пулю если она вышла за экран
28        elif bullet.x < 0:
29            yellow_bullets.remove(bullet)

Данная функция передвигает выстрелы, проверяет вылеты пули за экран, при этом удаляя пулю из листа, а так же проверяет попадание пули в корабли (метод colliderect) и если попадание случилось - вызывает соответствующее пользовательское событие.

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

Добавьте в бесконечный цикл следующий код:

1# Перебираем пули красного и рисуем каждый кадр
2for bullet in red_bullets:
3    pygame.draw.rect(screen, "red", bullet)
4# Перебираем пули желтого и рисуем каждый кадр
5for bullet in yellow_bullets:
6    pygame.draw.rect(screen, "yellow", bullet)

Каждый кадр мы проверяем наличие пуль в листе и рисуем их.

Ура! Теперь наши корабли стреляют!

Промежуточный результат #7

Работает:

- Кнопка закрыть/свернуть

- Отображается задний фон

- Разделитель экрана

- Отрисовка игроков

- Движение игроков

- Ограничитель кадров

- Здоровье игроков

- Выстрелы кораблей

1# Подключаем игровой движок Pygame
2import pygame
3# Подключаем модуль для работы с файловой системой
4import os
5
6# Подготавливаем необходимые модули Pygame
7pygame.init()
8
9### Константы ###
10# Константы размера окна
11WIDTH = 600
12HEIGHT = 300
13# Размеры корабля
14SPACESHIP_WIDTH = 55
15SPACESHIP_HEIGHT = 40
16# Скорость корабля
17VELOCITY = 5
18# Количество кадров в секунду
19FPS = 60
20# Шрифт здоровья
21HEALTH_FONT = pygame.font.SysFont('comicsans', 20)
22# Пользовательские события попаданий
23YELLOW_HIT = pygame.USEREVENT + 1
24RED_HIT = pygame.USEREVENT + 2
25
26# Ограничитель кадров
27clock = pygame.time.Clock()
28
29# Задаем размеры игрового окна
30screen = pygame.display.set_mode((WIDTH, HEIGHT))
31
32# Загружаем изображение в память
33SPACE_IMAGE = pygame.image.load(os.path.join('./assets', 'space.jpg'))
34
35# Создаем объект фона с разрешением окна
36SPACE_BG = pygame.transform.scale(SPACE_IMAGE, (WIDTH, HEIGHT))
37
38# Формируем объект границы
39BORDER = pygame.Rect(WIDTH//2 - 2, 0, 4, HEIGHT)
40
41# Загружаем изображение красного корабля 
42RED_SPACESHIP_IMAGE = pygame.image.load(
43    os.path.join('./assets', 'spaceship_red.png'))
44# Разворачиваем изображение в нужном направлении
45RED_SPACESHIP = pygame.transform.rotate(pygame.transform.scale(
46    RED_SPACESHIP_IMAGE, (SPACESHIP_WIDTH, SPACESHIP_HEIGHT)), 90)
47
48# Загружаем изображение желтого корабля 
49YELLOW_SPACESHIP_IMAGE = pygame.image.load(
50    os.path.join('./assets', 'spaceship_yellow.png'))
51# Разворачиваем изображение в нужном направлении
52YELLOW_SPACESHIP = pygame.transform.rotate(pygame.transform.scale(
53    YELLOW_SPACESHIP_IMAGE, (SPACESHIP_WIDTH, SPACESHIP_HEIGHT)), 270)
54
55# Создаем два объекта/прямоугольника
56red = pygame.Rect(100, 150, SPACESHIP_WIDTH, SPACESHIP_HEIGHT)
57yellow = pygame.Rect(500, 150, SPACESHIP_WIDTH, SPACESHIP_HEIGHT)
58
59# Здоровье игроков
60red_health = 10
61yellow_health = 10
62
63# Хранение выпущенных пуль
64red_bullets = []
65yellow_bullets = []
66# Макс. выпущенных пуль
67MAX_BULLETS = 3
68# Скорость пули
69BULLET_VEL = 7
70
71# Функция движения красного корабля
72def red_handle_movement(keys_pressed, red):
73    # Движение ВЛЕВО
74    if keys_pressed[pygame.K_a] and red.x - VELOCITY > 0:
75        red.x -= VELOCITY
76    # Движение ВПРАВО (запрещаем пересекать границу игроков)
77    if keys_pressed[pygame.K_d] and red.x + VELOCITY + red.width < BORDER.x:
78        red.x += VELOCITY
79    # Движение ВВЕРХ (запрещаем подниматься выше 0 по координате y)
80    if keys_pressed[pygame.K_w] and red.y - VELOCITY > 0:
81        red.y -= VELOCITY
82    # Движение ВНИЗ (запрещаем опускаться ниже чем высота экрана за вычетом высоты корабля и дополнительных 15 для отступа)
83    if keys_pressed[pygame.K_s] and red.y + VELOCITY + red.height < HEIGHT - 15:
84        red.y += VELOCITY
85
86# Функция движения желтого корабля
87def yellow_handle_movement(keys_pressed, yellow):
88    # Движение ВЛЕВО (запрещаем пересекать границу игроков)
89    if keys_pressed[pygame.K_LEFT] and yellow.x - VELOCITY > BORDER.x + BORDER.width:
90        yellow.x -= VELOCITY
91    # Движение ВПРАВО
92    if keys_pressed[pygame.K_RIGHT] and yellow.x + VELOCITY + yellow.width < WIDTH:
93        yellow.x += VELOCITY
94    # Движение ВВЕРХ
95    if keys_pressed[pygame.K_UP] and yellow.y - VELOCITY > 0:
96        yellow.y -= VELOCITY
97    # Движение ВНИЗ
98    if keys_pressed[pygame.K_DOWN] and yellow.y + VELOCITY + yellow.height < HEIGHT - 15:
99        yellow.y += VELOCITY
100
101# Обработка выпущенных пуль
102def handle_bullets(yellow_bullets, red_bullets, yellow, red):
103    # Перебираем все пули красного
104    for bullet in red_bullets:
105        # Двигаем пулю вправо
106        bullet.x += BULLET_VEL
107        # Если пуля задевает желтого игрока
108        if yellow.colliderect(bullet):
109            # Вызываем пользовательское событие попадание в Желтого
110            pygame.event.post(pygame.event.Event(YELLOW_HIT))
111            # Удаляем текущую пулю
112            red_bullets.remove(bullet)
113        # Удаляем пулю если она вышла за экран
114        elif bullet.x > WIDTH:
115            red_bullets.remove(bullet)
116
117    # Перебираем все пули желтого
118    for bullet in yellow_bullets:
119        # Двигаем пулю влево
120        bullet.x -= BULLET_VEL
121        # Если пуля задевает красного игрока
122        if red.colliderect(bullet):
123            # Вызываем пользовательское событие попадание в Красного
124            pygame.event.post(pygame.event.Event(RED_HIT))
125            # Удаляем текущую пулю
126            yellow_bullets.remove(bullet)
127        # Удаляем пулю если она вышла за экран
128        elif bullet.x < 0:
129            yellow_bullets.remove(bullet)
130
131
132# Запускаем бесконечный цикл программы
133# Это делается чтобы программа не завершалась и постоянно рисовала новые кадры игры
134while True:
135    # Ограничиваем количество кадров игры
136    clock.tick(FPS)
137
138    # Рисуем изображение на заднем фоне
139    screen.blit(SPACE_BG, (0, 0))
140
141    # Рисуем прямоугольник 
142    pygame.draw.rect(screen, "white", BORDER)
143
144    # Рисуем корабли
145    screen.blit(YELLOW_SPACESHIP, (yellow.x, yellow.y))
146    screen.blit(RED_SPACESHIP, (red.x, red.y))
147
148    # Отображаем здоровье на экране
149    red_health_text = HEALTH_FONT.render(
150        "Health: " + str(red_health), 1, "white")
151    yellow_health_text = HEALTH_FONT.render(
152        "Health: " + str(yellow_health), 1, "white")
153    screen.blit(red_health_text, (10, 10))
154    screen.blit(yellow_health_text, (WIDTH - red_health_text.get_width() - 10, 10))
155
156    # Постоянно проверяем события игры и если присутствует событие Выход - останавливаем игру.
157    for event in pygame.event.get():
158        if event.type == pygame.QUIT:
159            pygame.quit()
160
161        # Если произошло событие нажатия клавиши
162        if event.type == pygame.KEYDOWN:
163            # И нажали клавишу Пробел, а так же если длина листа выпущенных пуль красного меньше минимального
164            if event.key == pygame.K_SPACE and len(red_bullets) < MAX_BULLETS:
165                # Создаем объект прямоугольника для Пули
166                bullet = pygame.Rect(
167                    red.x + red.width, red.y + red.height//2 - 2, 10, 5)
168                # Добавляем выпущенную пулю красному
169                red_bullets.append(bullet)
170
171            # Если нажали клавишу Enter, создаем выпущенную пулю желтому игроку
172            if event.key == pygame.K_RETURN and len(yellow_bullets) < MAX_BULLETS:
173                # Создаем объект прямоугольника для Пули
174                bullet = pygame.Rect(
175                    yellow.x, yellow.y + yellow.height//2 - 2, 10, 5)
176                # Добавляем выпущенную пулю желтому
177                yellow_bullets.append(bullet)
178
179    # Узнаем нажатие клавишей
180    keys_pressed = pygame.key.get_pressed()
181    # Выполняем установку координат кораблей
182    red_handle_movement(keys_pressed, red)
183    yellow_handle_movement(keys_pressed, yellow)
184
185    # Проверяем столкновения пуль
186    handle_bullets(yellow_bullets, red_bullets, yellow, red)
187
188    # Перебираем пули красного и рисуем каждый кадр
189    for bullet in red_bullets:
190        pygame.draw.rect(screen, "red", bullet)
191    # Перебираем пули желтого и рисуем каждый кадр
192    for bullet in yellow_bullets:
193        pygame.draw.rect(screen, "yellow", bullet)
194
195    # Обновляем кадры игры
196    pygame.display.update()
197

Учет попаданий - Отображение победителя

Теперь нужно при попадании уменьшать здоровье игроков. Ранее мы создали пользовательские события RED_HIT и YELLOW_HIT и при попадании в соответствующего игрока вызвали соответствующее событие. Теперь достаточно обработать эти события.

Добавьте этот код к участку кода где мы проверяли события нажатия кнопки выйти и нажатия кнопок Space (Пробел) и Enter.

1# Если случилось пользовательское событие RED_HIT отнимаем жизни у Красного
2if event.type == RED_HIT:
3    red_health -= 1
4
5# Если случилось пользовательское событие YELLOW_HIT отнимаем жизни у Желтого
6if event.type == YELLOW_HIT:  
7    yellow_health -= 1

Если случилось пользовательское событие RED_HIT отнимаем жизни у Красного, если событие YELLOW_HIT отнимаем жизни у Желтого. Думаю теперь стало понятно для чего мы делали пользовательские события. Проверьте. Теперь здоровье должно отниматься, и визуально тоже.

Сейчас здоровье может уходить в минус. Давайте будем проверять - если здоровье упало до нуля, покажем сообщение - Имя победителя, а затем обнулим игровые счетчики.

Напишите следующую функцию:

1# Функция рисует экран победителя
2def draw_winner(text):
3    # Создаем шрифт для победителя
4    WINNER_FONT = pygame.font.SysFont('comicsans', 60)
5    # Создаем надпись
6    draw_text = WINNER_FONT.render(text, 1, 'white')
7    # Устанавливаем надпись в центре игрового поля
8    screen.blit(draw_text, (WIDTH/2 - draw_text.get_width() /
9                         2, HEIGHT/2 - draw_text.get_height()/2))
10    
11    # Обновляем кадр игры
12    pygame.display.update()
13    # Задержка после победы
14    pygame.time.delay(2000)

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

Теперь в секции бесконечного цикла добавьте этот код:

1# Если здоровье упало до нуля, рисуем имя победителя.
2winner_text = ""
3if red_health <= 0:
4    winner_text = "Yellow Wins!"
5
6if yellow_health <= 0:
7    winner_text = "Red Wins!"
8
9if winner_text != "":
10    draw_winner(winner_text)
11    # Обнуляем пули
12    red_bullets.clear()
13    yellow_bullets.clear()
14    # Восстанавливаем здоровье
15    red_health = 10
16    yellow_health = 10

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

Поздравляю - база игры готова!

Основа игры.
Основа игры.

Промежуточный результат #8

Работает:

- Кнопка закрыть/свернуть

- Отображается задний фон

- Разделитель экрана

- Отрисовка игроков

- Движение игроков

- Ограничитель кадров

- Здоровье игроков

- Выстрелы кораблей

- Экран победителя и обнуление показателей

1# Подключаем игровой движок Pygame
2import pygame
3# Подключаем модуль для работы с файловой системой
4import os
5
6# Подготавливаем необходимые модули Pygame
7pygame.init()
8
9### Константы ###
10# Константы размера окна
11WIDTH = 600
12HEIGHT = 300
13# Размеры корабля
14SPACESHIP_WIDTH = 55
15SPACESHIP_HEIGHT = 40
16# Скорость корабля
17VELOCITY = 5
18# Количество кадров в секунду
19FPS = 60
20# Шрифт здоровья
21HEALTH_FONT = pygame.font.SysFont('comicsans', 20)
22# Пользовательские события попаданий
23YELLOW_HIT = pygame.USEREVENT + 1
24RED_HIT = pygame.USEREVENT + 2
25
26# Ограничитель кадров
27clock = pygame.time.Clock()
28
29# Задаем размеры игрового окна
30screen = pygame.display.set_mode((WIDTH, HEIGHT))
31
32# Загружаем изображение в память
33SPACE_IMAGE = pygame.image.load(os.path.join('./assets', 'space.jpg'))
34
35# Создаем объект фона с разрешением окна
36SPACE_BG = pygame.transform.scale(SPACE_IMAGE, (WIDTH, HEIGHT))
37
38# Формируем объект границы
39BORDER = pygame.Rect(WIDTH//2 - 2, 0, 4, HEIGHT)
40
41# Загружаем изображение красного корабля 
42RED_SPACESHIP_IMAGE = pygame.image.load(
43    os.path.join('./assets', 'spaceship_red.png'))
44# Разворачиваем изображение в нужном направлении
45RED_SPACESHIP = pygame.transform.rotate(pygame.transform.scale(
46    RED_SPACESHIP_IMAGE, (SPACESHIP_WIDTH, SPACESHIP_HEIGHT)), 90)
47
48# Загружаем изображение желтого корабля 
49YELLOW_SPACESHIP_IMAGE = pygame.image.load(
50    os.path.join('./assets', 'spaceship_yellow.png'))
51# Разворачиваем изображение в нужном направлении
52YELLOW_SPACESHIP = pygame.transform.rotate(pygame.transform.scale(
53    YELLOW_SPACESHIP_IMAGE, (SPACESHIP_WIDTH, SPACESHIP_HEIGHT)), 270)
54
55# Создаем два объекта/прямоугольника
56red = pygame.Rect(100, 150, SPACESHIP_WIDTH, SPACESHIP_HEIGHT)
57yellow = pygame.Rect(500, 150, SPACESHIP_WIDTH, SPACESHIP_HEIGHT)
58
59# Здоровье игроков
60red_health = 10
61yellow_health = 10
62
63# Хранение выпущенных пуль
64red_bullets = []
65yellow_bullets = []
66# Макс. выпущенных пуль
67MAX_BULLETS = 3
68# Скорость пули
69BULLET_VEL = 7
70
71# Функция движения красного корабля
72def red_handle_movement(keys_pressed, red):
73    # Движение ВЛЕВО
74    if keys_pressed[pygame.K_a] and red.x - VELOCITY > 0:
75        red.x -= VELOCITY
76    # Движение ВПРАВО (запрещаем пересекать границу игроков)
77    if keys_pressed[pygame.K_d] and red.x + VELOCITY + red.width < BORDER.x:
78        red.x += VELOCITY
79    # Движение ВВЕРХ (запрещаем подниматься выше 0 по координате y)
80    if keys_pressed[pygame.K_w] and red.y - VELOCITY > 0:
81        red.y -= VELOCITY
82    # Движение ВНИЗ (запрещаем опускаться ниже чем высота экрана за вычетом высоты корабля и дополнительных 15 для отступа)
83    if keys_pressed[pygame.K_s] and red.y + VELOCITY + red.height < HEIGHT - 15:
84        red.y += VELOCITY
85
86# Функция движения желтого корабля
87def yellow_handle_movement(keys_pressed, yellow):
88    # Движение ВЛЕВО (запрещаем пересекать границу игроков)
89    if keys_pressed[pygame.K_LEFT] and yellow.x - VELOCITY > BORDER.x + BORDER.width:
90        yellow.x -= VELOCITY
91    # Движение ВПРАВО
92    if keys_pressed[pygame.K_RIGHT] and yellow.x + VELOCITY + yellow.width < WIDTH:
93        yellow.x += VELOCITY
94    # Движение ВВЕРХ
95    if keys_pressed[pygame.K_UP] and yellow.y - VELOCITY > 0:
96        yellow.y -= VELOCITY
97    # Движение ВНИЗ
98    if keys_pressed[pygame.K_DOWN] and yellow.y + VELOCITY + yellow.height < HEIGHT - 15:
99        yellow.y += VELOCITY
100
101# Обработка выпущенных пуль
102def handle_bullets(yellow_bullets, red_bullets, yellow, red):
103    # Перебираем все пули красного
104    for bullet in red_bullets:
105        # Двигаем пулю вправо
106        bullet.x += BULLET_VEL
107        # Если пуля задевает желтого игрока
108        if yellow.colliderect(bullet):
109            # Вызываем пользовательское событие попадание в Желтого
110            pygame.event.post(pygame.event.Event(YELLOW_HIT))
111            # Удаляем текущую пулю
112            red_bullets.remove(bullet)
113        # Удаляем пулю если она вышла за экран
114        elif bullet.x > WIDTH:
115            red_bullets.remove(bullet)
116
117    # Перебираем все пули желтого
118    for bullet in yellow_bullets:
119        # Двигаем пулю влево
120        bullet.x -= BULLET_VEL
121        # Если пуля задевает красного игрока
122        if red.colliderect(bullet):
123            # Вызываем пользовательское событие попадание в Красного
124            pygame.event.post(pygame.event.Event(RED_HIT))
125            # Удаляем текущую пулю
126            yellow_bullets.remove(bullet)
127        # Удаляем пулю если она вышла за экран
128        elif bullet.x < 0:
129            yellow_bullets.remove(bullet)
130
131# Функция рисует экран победителя
132def draw_winner(text):
133    # Создаем шрифт для победителя
134    WINNER_FONT = pygame.font.SysFont('comicsans', 60)
135    # Создаем надпись
136    draw_text = WINNER_FONT.render(text, 1, 'white')
137    # Устанавливаем надпись в центре игрового поля
138    screen.blit(draw_text, (WIDTH/2 - draw_text.get_width() /
139                         2, HEIGHT/2 - draw_text.get_height()/2))
140    
141    # Обновляем кадр игры
142    pygame.display.update()
143    # Задержка после победы
144    pygame.time.delay(2000)
145
146# Запускаем бесконечный цикл программы
147# Это делается чтобы программа не завершалась и постоянно рисовала новые кадры игры
148while True:
149    # Ограничиваем количество кадров игры
150    clock.tick(FPS)
151
152    # Рисуем изображение на заднем фоне
153    screen.blit(SPACE_BG, (0, 0))
154
155    # Рисуем прямоугольник 
156    pygame.draw.rect(screen, "white", BORDER)
157
158    # Рисуем корабли
159    screen.blit(YELLOW_SPACESHIP, (yellow.x, yellow.y))
160    screen.blit(RED_SPACESHIP, (red.x, red.y))
161
162    # Отображаем здоровье на экране
163    red_health_text = HEALTH_FONT.render(
164        "Health: " + str(red_health), 1, "white")
165    yellow_health_text = HEALTH_FONT.render(
166        "Health: " + str(yellow_health), 1, "white")
167    screen.blit(red_health_text, (10, 10))
168    screen.blit(yellow_health_text, (WIDTH - red_health_text.get_width() - 10, 10))
169
170    # Постоянно проверяем события игры и если присутствует событие Выход - останавливаем игру.
171    for event in pygame.event.get():
172        if event.type == pygame.QUIT:
173            pygame.quit()
174
175        # Если случилось пользовательское событие RED_HIT отнимаем жизни у Красного
176        if event.type == RED_HIT:
177            red_health -= 1
178
179        # Если случилось пользовательское событие YELLOW_HIT отнимаем жизни у Желтого
180        if event.type == YELLOW_HIT:
181            yellow_health -= 1
182
183        # Если произошло событие нажатия клавиши
184        if event.type == pygame.KEYDOWN:
185            # И нажали клавишу Пробел, а так же если длина листа выпущенных пуль красного меньше минимального
186            if event.key == pygame.K_SPACE and len(red_bullets) < MAX_BULLETS:
187                # Создаем объект прямоугольника для Пули
188                bullet = pygame.Rect(
189                    red.x + red.width, red.y + red.height//2 - 2, 10, 5)
190                # Добавляем выпущенную пулю красному
191                red_bullets.append(bullet)
192
193            # Если нажали клавишу Enter, создаем выпущенную пулю желтому игроку
194            if event.key == pygame.K_RETURN and len(yellow_bullets) < MAX_BULLETS:
195                # Создаем объект прямоугольника для Пули
196                bullet = pygame.Rect(
197                    yellow.x, yellow.y + yellow.height//2 - 2, 10, 5)
198                # Добавляем выпущенную пулю желтому
199                yellow_bullets.append(bullet)
200
201    # Узнаем нажатие клавишей
202    keys_pressed = pygame.key.get_pressed()
203    # Выполняем установку координат кораблей
204    red_handle_movement(keys_pressed, red)
205    yellow_handle_movement(keys_pressed, yellow)
206
207    # Проверяем столкновения пуль
208    handle_bullets(yellow_bullets, red_bullets, yellow, red)
209
210    # Перебираем пули красного и рисуем каждый кадр
211    for bullet in red_bullets:
212        pygame.draw.rect(screen, "red", bullet)
213    # Перебираем пули желтого и рисуем каждый кадр
214    for bullet in yellow_bullets:
215        pygame.draw.rect(screen, "yellow", bullet)
216
217    # Если здоровье упало до нуля, рисуем имя победителя.
218    winner_text = ""
219    if red_health <= 0:
220        winner_text = "Yellow Wins!"
221
222    if yellow_health <= 0:
223        winner_text = "Red Wins!"
224
225    if winner_text != "":
226        draw_winner(winner_text)
227        # Обнуляем пули
228        red_bullets.clear()
229        yellow_bullets.clear()
230        # Восстанавливаем здоровье
231        red_health = 10
232        yellow_health = 10
233
234    # Обновляем кадры игры
235    pygame.display.update()

Звуки

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

Скачайте два звука grenade.mp3 и silencer.mp3 по этой ссылке и положите их в папку assets.

В самом верху нашего кода, там где импортировали модули, добавьте строчку (секция Подготавливаем необходимые модули Pygame):

1pygame.mixer.init()

Данная строчка инициализирует модуль работы со звуками.

Теперь подключим два наших звука к игре.

1# Подключаем звуки к игре
2# Звук попадания
3BULLET_HIT_SOUND = pygame.mixer.Sound('./assets/grenade.mp3')
4# Звук выстрела
5BULLET_FIRE_SOUND = pygame.mixer.Sound('./assets/silencer.mp3')

Теперь необходимо расставить нужные звуки в нужных местах. Добавьте строчку BULLET_HIT_SOUND.play() в местах где мы отнимаем здоровье (обрабатываем попадание)

1# Если случилось пользовательское событие RED_HIT отнимаем жизни у Красного
2if event.type == RED_HIT:
3    red_health -= 1
4    # Звук попадания
5    BULLET_HIT_SOUND.play()
6
7# Если случилось пользовательское событие YELLOW_HIT отнимаем жизни у Желтого
8if event.type == YELLOW_HIT:
9    yellow_health -= 1
10    # Звук попадания
11    BULLET_HIT_SOUND.play()

Так же добавьте строчку BULLET_FIRE_SOUND.play() в местах где мы создаем пули при нажатии кнопок:

1# Если произошло событие нажатия клавиши
2if event.type == pygame.KEYDOWN:
3    # И нажали клавишу Пробел, а так же если длина листа выпущенных пуль красного меньше минимального
4    if event.key == pygame.K_SPACE and len(red_bullets) < MAX_BULLETS:
5        # Создаем объект прямоугольника для Пули
6        bullet = pygame.Rect(
7            red.x + red.width, red.y + red.height//2 - 2, 10, 5)
8        # Добавляем выпущенную пулю красному
9        red_bullets.append(bullet)
10        # Звук выстрела
11        BULLET_FIRE_SOUND.play()
12
13    # Если нажали клавишу Enter, создаем выпущенную пулю желтому игроку
14    if event.key == pygame.K_RETURN and len(yellow_bullets) < MAX_BULLETS:
15        # Создаем объект прямоугольника для Пули
16        bullet = pygame.Rect(
17            yellow.x, yellow.y + yellow.height//2 - 2, 10, 5)
18        # Добавляем выпущенную пулю желтому
19        yellow_bullets.append(bullet)
20        # Звук выстрела
21        BULLET_FIRE_SOUND.play()

Так намного лучше! Игра заиграла новыми красками!

Итоговый результат

Работает:

- Кнопка закрыть/свернуть

- Отображается задний фон

- Разделитель экрана

- Отрисовка игроков

- Движение игроков

- Ограничитель кадров

- Здоровье игроков

- Выстрелы кораблей

- Звуки выстрелов и попаданий

1# Подключаем игровой движок Pygame
2import pygame
3# Подключаем модуль для работы с файловой системой
4import os
5
6# Подготавливаем необходимые модули Pygame
7pygame.init()
8pygame.mixer.init()
9
10# Подключаем звуки к игре
11# Звук попадания
12BULLET_HIT_SOUND = pygame.mixer.Sound('./assets/grenade.mp3')
13# Звук выстрела
14BULLET_FIRE_SOUND = pygame.mixer.Sound('./assets/silencer.mp3')
15
16### Константы ###
17# Константы размера окна
18WIDTH = 600
19HEIGHT = 300
20# Размеры корабля
21SPACESHIP_WIDTH = 55
22SPACESHIP_HEIGHT = 40
23# Скорость корабля
24VELOCITY = 5
25# Количество кадров в секунду
26FPS = 60
27# Шрифт здоровья
28HEALTH_FONT = pygame.font.SysFont('comicsans', 20)
29# Пользовательские события попаданий
30YELLOW_HIT = pygame.USEREVENT + 1
31RED_HIT = pygame.USEREVENT + 2
32
33# Ограничитель кадров
34clock = pygame.time.Clock()
35
36# Задаем размеры игрового окна
37screen = pygame.display.set_mode((WIDTH, HEIGHT))
38
39# Загружаем изображение в память
40SPACE_IMAGE = pygame.image.load(os.path.join('./assets', 'space.jpg'))
41
42# Создаем объект фона с разрешением окна
43SPACE_BG = pygame.transform.scale(SPACE_IMAGE, (WIDTH, HEIGHT))
44
45# Формируем объект границы
46BORDER = pygame.Rect(WIDTH//2 - 2, 0, 4, HEIGHT)
47
48# Загружаем изображение красного корабля 
49RED_SPACESHIP_IMAGE = pygame.image.load(
50    os.path.join('./assets', 'spaceship_red.png'))
51# Разворачиваем изображение в нужном направлении
52RED_SPACESHIP = pygame.transform.rotate(pygame.transform.scale(
53    RED_SPACESHIP_IMAGE, (SPACESHIP_WIDTH, SPACESHIP_HEIGHT)), 90)
54
55# Загружаем изображение желтого корабля 
56YELLOW_SPACESHIP_IMAGE = pygame.image.load(
57    os.path.join('./assets', 'spaceship_yellow.png'))
58# Разворачиваем изображение в нужном направлении
59YELLOW_SPACESHIP = pygame.transform.rotate(pygame.transform.scale(
60    YELLOW_SPACESHIP_IMAGE, (SPACESHIP_WIDTH, SPACESHIP_HEIGHT)), 270)
61
62# Создаем два объекта/прямоугольника
63red = pygame.Rect(100, 150, SPACESHIP_WIDTH, SPACESHIP_HEIGHT)
64yellow = pygame.Rect(500, 150, SPACESHIP_WIDTH, SPACESHIP_HEIGHT)
65
66# Здоровье игроков
67red_health = 10
68yellow_health = 10
69
70# Хранение выпущенных пуль
71red_bullets = []
72yellow_bullets = []
73# Макс. выпущенных пуль
74MAX_BULLETS = 3
75# Скорость пули
76BULLET_VEL = 7
77
78# Функция движения красного корабля
79def red_handle_movement(keys_pressed, red):
80    # Движение ВЛЕВО
81    if keys_pressed[pygame.K_a] and red.x - VELOCITY > 0:
82        red.x -= VELOCITY
83    # Движение ВПРАВО (запрещаем пересекать границу игроков)
84    if keys_pressed[pygame.K_d] and red.x + VELOCITY + red.width < BORDER.x:
85        red.x += VELOCITY
86    # Движение ВВЕРХ (запрещаем подниматься выше 0 по координате y)
87    if keys_pressed[pygame.K_w] and red.y - VELOCITY > 0:
88        red.y -= VELOCITY
89    # Движение ВНИЗ (запрещаем опускаться ниже чем высота экрана за вычетом высоты корабля и дополнительных 15 для отступа)
90    if keys_pressed[pygame.K_s] and red.y + VELOCITY + red.height < HEIGHT - 15:
91        red.y += VELOCITY
92
93# Функция движения желтого корабля
94def yellow_handle_movement(keys_pressed, yellow):
95    # Движение ВЛЕВО (запрещаем пересекать границу игроков)
96    if keys_pressed[pygame.K_LEFT] and yellow.x - VELOCITY > BORDER.x + BORDER.width:
97        yellow.x -= VELOCITY
98    # Движение ВПРАВО
99    if keys_pressed[pygame.K_RIGHT] and yellow.x + VELOCITY + yellow.width < WIDTH:
100        yellow.x += VELOCITY
101    # Движение ВВЕРХ
102    if keys_pressed[pygame.K_UP] and yellow.y - VELOCITY > 0:
103        yellow.y -= VELOCITY
104    # Движение ВНИЗ
105    if keys_pressed[pygame.K_DOWN] and yellow.y + VELOCITY + yellow.height < HEIGHT - 15:
106        yellow.y += VELOCITY
107
108# Обработка выпущенных пуль
109def handle_bullets(yellow_bullets, red_bullets, yellow, red):
110    # Перебираем все пули красного
111    for bullet in red_bullets:
112        # Двигаем пулю вправо
113        bullet.x += BULLET_VEL
114        # Если пуля задевает желтого игрока
115        if yellow.colliderect(bullet):
116            # Вызываем пользовательское событие попадание в Желтого
117            pygame.event.post(pygame.event.Event(YELLOW_HIT))
118            # Удаляем текущую пулю
119            red_bullets.remove(bullet)
120        # Удаляем пулю если она вышла за экран
121        elif bullet.x > WIDTH:
122            red_bullets.remove(bullet)
123
124    # Перебираем все пули желтого
125    for bullet in yellow_bullets:
126        # Двигаем пулю влево
127        bullet.x -= BULLET_VEL
128        # Если пуля задевает красного игрока
129        if red.colliderect(bullet):
130            # Вызываем пользовательское событие попадание в Красного
131            pygame.event.post(pygame.event.Event(RED_HIT))
132            # Удаляем текущую пулю
133            yellow_bullets.remove(bullet)
134        # Удаляем пулю если она вышла за экран
135        elif bullet.x < 0:
136            yellow_bullets.remove(bullet)
137
138# Функция рисует экран победителя
139def draw_winner(text):
140    # Создаем шрифт для победителя
141    WINNER_FONT = pygame.font.SysFont('comicsans', 60)
142    # Создаем надпись
143    draw_text = WINNER_FONT.render(text, 1, 'white')
144    # Устанавливаем надпись в центре игрового поля
145    screen.blit(draw_text, (WIDTH/2 - draw_text.get_width() /
146                         2, HEIGHT/2 - draw_text.get_height()/2))
147    
148    # Обновляем кадр игры
149    pygame.display.update()
150    # Задержка после победы
151    pygame.time.delay(2000)
152
153# Запускаем бесконечный цикл программы
154# Это делается чтобы программа не завершалась и постоянно рисовала новые кадры игры
155while True:
156    # Ограничиваем количество кадров игры
157    clock.tick(FPS)
158
159    # Рисуем изображение на заднем фоне
160    screen.blit(SPACE_BG, (0, 0))
161
162    # Рисуем прямоугольник 
163    pygame.draw.rect(screen, "white", BORDER)
164
165    # Рисуем корабли
166    screen.blit(YELLOW_SPACESHIP, (yellow.x, yellow.y))
167    screen.blit(RED_SPACESHIP, (red.x, red.y))
168
169    # Отображаем здоровье на экране
170    red_health_text = HEALTH_FONT.render(
171        "Health: " + str(red_health), 1, "white")
172    yellow_health_text = HEALTH_FONT.render(
173        "Health: " + str(yellow_health), 1, "white")
174    screen.blit(red_health_text, (10, 10))
175    screen.blit(yellow_health_text, (WIDTH - red_health_text.get_width() - 10, 10))
176
177    # Постоянно проверяем события игры и если присутствует событие Выход - останавливаем игру.
178    for event in pygame.event.get():
179        if event.type == pygame.QUIT:
180            pygame.quit()
181
182        # Если случилось пользовательское событие RED_HIT отнимаем жизни у Красного
183        if event.type == RED_HIT:
184            red_health -= 1
185            # Звук попадания
186            BULLET_HIT_SOUND.play()
187
188        # Если случилось пользовательское событие YELLOW_HIT отнимаем жизни у Желтого
189        if event.type == YELLOW_HIT:
190            yellow_health -= 1
191            # Звук попадания
192            BULLET_HIT_SOUND.play()
193
194        # Если произошло событие нажатия клавиши
195        if event.type == pygame.KEYDOWN:
196            # И нажали клавишу Пробел, а так же если длина листа выпущенных пуль красного меньше минимального
197            if event.key == pygame.K_SPACE and len(red_bullets) < MAX_BULLETS:
198                # Создаем объект прямоугольника для Пули
199                bullet = pygame.Rect(
200                    red.x + red.width, red.y + red.height//2 - 2, 10, 5)
201                # Добавляем выпущенную пулю красному
202                red_bullets.append(bullet)
203                # Звук выстрела
204                BULLET_FIRE_SOUND.play()
205
206            # Если нажали клавишу Enter, создаем выпущенную пулю желтому игроку
207            if event.key == pygame.K_RETURN and len(yellow_bullets) < MAX_BULLETS:
208                # Создаем объект прямоугольника для Пули
209                bullet = pygame.Rect(
210                    yellow.x, yellow.y + yellow.height//2 - 2, 10, 5)
211                # Добавляем выпущенную пулю желтому
212                yellow_bullets.append(bullet)
213                # Звук выстрела
214                BULLET_FIRE_SOUND.play()
215
216    # Узнаем нажатие клавишей
217    keys_pressed = pygame.key.get_pressed()
218    # Выполняем установку координат кораблей
219    red_handle_movement(keys_pressed, red)
220    yellow_handle_movement(keys_pressed, yellow)
221
222    # Проверяем столкновения пуль
223    handle_bullets(yellow_bullets, red_bullets, yellow, red)
224
225    # Перебираем пули красного и рисуем каждый кадр
226    for bullet in red_bullets:
227        pygame.draw.rect(screen, "red", bullet)
228    # Перебираем пули желтого и рисуем каждый кадр
229    for bullet in yellow_bullets:
230        pygame.draw.rect(screen, "yellow", bullet)
231
232    # Если здоровье упало до нуля, рисуем имя победителя.
233    winner_text = ""
234    if red_health <= 0:
235        winner_text = "Yellow Wins!"
236
237    if yellow_health <= 0:
238        winner_text = "Red Wins!"
239
240    if winner_text != "":
241        draw_winner(winner_text)
242        # Обнуляем пули
243        red_bullets.clear()
244        yellow_bullets.clear()
245        # Восстанавливаем здоровье
246        red_health = 10
247        yellow_health = 10
248
249    # Обновляем кадры игры
250    pygame.display.update()

Поздравляю! Наша игра готова! Теперь можно подумать как ее улучшить. Например, добавить новые звуки, создать возможность собирать powerup-ы и т.д.

Заключение

Библиотека PyGame не предоставит вам инструмента для создания AAA-игры, но для обучения вполне подходящий инструмент. С помощью PyGame легко рисовать фигуры, добавлять на них текстуры, работать с нажатиями клавиш и звуком. Все что нужно для Indie игры. Вот, кстати несколько примеров таких игр.

Если же хочется большего, думаю, стоит присмотреться к игровому движку Godot. Язык программирования Godot Script очень похож на Python, так что разобраться будет не сложно, а проекты там на порядок выше. Вот пример.

Надеюсь данная статься была вам интересна и вы нашли в ней что-то полезное! Удачи!



Поделиться: