Враги в играх на Python с библиотекой Arcade — практическое руководство

Враги играют ключевую роль в создании интересных и сложных игр. Они создают препятствия и противников для игрока, делая игровой процесс более захватывающим. Библиотека Arcade для Python предоставляет простой и понятный набор инструментов для добавления врагов в ваши проекты.
Создайте простую игру
Перед началом убедитесь, что на вашем устройстве установлен pip. Установите библиотеку Arcade командой:
pip install arcadeДалее создайте простую игру, где игрок может передвигаться влево и вправо стрелками. Ниже — минимальный рабочий пример окна и движения игрока.
import arcade
# Window dimensions
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
# Player attributes
PLAYER_RADIUS = 25
PLAYER_SPEED = 5
class GameWindow(arcade.Window):
def __init__(self, width, height):
super().__init__(width, height)
arcade.set_background_color(arcade.color.WHITE)
self.player_x = width // 2
def on_draw(self):
arcade.start_render()
arcade.draw_circle_filled(self.player_x, PLAYER_RADIUS, PLAYER_RADIUS, arcade.color.BLUE)
def on_key_press(self, key, modifiers):
if key == arcade.key.LEFT:
self.player_x -= PLAYER_SPEED
elif key == arcade.key.RIGHT:
self.player_x += PLAYER_SPEED
def update(self, delta_time):
pass
def main():
window = GameWindow(SCREEN_WIDTH, SCREEN_HEIGHT)
arcade.run()
if __name__ == "__main__":
main()Код в статье хранится в репозитории GitHub и доступен по MIT‑лицензии — вы можете его использовать и модифицировать.
Создание простого врага
Чтобы сделать врага, достаточно отрисовать ещё один круг (или спрайт) и проверять пересечение с игроком. В простейшем случае при столкновении можно объявлять «Game Over». Ниже — пример добавления статичного врага и функции проверки столкновений.
# Add to GameWindow class
class GameWindow(arcade.Window):
# ...
def __init__(self, width, height):
# ...
# Enemy attributes
self.enemy_x = width // 2
self.enemy_y = height - PLAYER_RADIUS
self.enemy_radius = 20
def on_draw(self):
# ...
arcade.draw_circle_filled(self.enemy_x, self.enemy_y, self.enemy_radius, arcade.color.RED)
def update(self, delta_time):
if self.is_collision(self.player_x, self.player_y, self.enemy_x, self.enemy_y, PLAYER_RADIUS, self.enemy_radius):
print("Game Over!")
def is_collision(self, x1, y1, x2, y2, radius1, radius2):
distance_squared = (x1 - x2) 2 + (y1 - y2) 2
radius_sum_squared = (radius1 + radius2) 2
return distance_squared <= radius_sum_squaredВажно: для точной работы коллизий убедитесь, что координаты игрока и врага (x, y) поддерживаются корректно в ваших методах управления и обновления.
Преследование игрока
Интересный элемент геймплея — враг, который преследует игрока. Это добавляет динамики и заставляет игрока маневрировать. Подсказка: для простоты обновляйте координату врага на каждой итерации update в направлении игрока. Создайте файл enemy-follow-player.py и примените логику ниже.
# Add to GameWindow class class GameWindow(arcade.Window): # ... def update(self, delta_time): if self.player_x < self.enemy_x: self.enemy_x -= PLAYER_SPEED elif self.player_x > self.enemy_x: self.enemy_x += PLAYER_SPEED if self.is_collision(self.player_x, self.player_y, self.enemy_x, self.enemy_y, PLAYER_RADIUS, ENEMY_RADIUS): print("Game Over!") def is_collision(self, x1, y1, x2, y2, radius1, radius2): distance_squared = (x1 - x2)2 + (y1 - y2) 2 radius_sum_squared = (radius1 + radius2) 2 return distance_squared <= radius_sum_squared
Ниже — визуализация поведения:
Совет: при большом количестве преследующих врагов уменьшайте частоту обновления логики движения или используйте упрощённые эвристики, чтобы не нагружать цикл обновления.
Пули от врага
Чтобы враг мог стрелять, добавьте класс Bullet и список активных пуль. Враг периодически создаёт новые пули, которые затем двигаются по сцене. Создайте файл bullets.py и добавьте следующий код:
# Add to GameWindow class
class Bullet:
def __init__(self, x, y, radius, speed):
self.x = x
self.y = y
self.radius = radius
self.speed = speed
def update(self):
self.y -= self.speed
class GameWindow(arcade.Window):
# ...
def __init__(self, width, height):
# ...
# Enemy attributes
self.bullets = []
self.bullet_radius = 5
self.bullet_speed = 3
self.bullet_cooldown = 60# Number of frames between bullet spawns
self.bullet_timer = 0
def on_draw(self):
# ...
for bullet in self.bullets:
arcade.draw_circle_filled(bullet.x, bullet.y,
self.bullet_radius, arcade.color.BLACK)
def update(self, delta_time):
# ...
self.bullet_timer += 1
if self.bullet_timer >= self.bullet_cooldown:
self.bullets.append(Bullet(self.enemy_x, self.enemy_y - self.enemy_radius,
self.bullet_radius, self.bullet_speed))
self.bullet_timer = 0
for bullet in self.bullets:
bullet.update()
if self.is_collision(self.player_x, self.player_y, self.enemy_x,
self.enemy_y, PLAYER_RADIUS, ENEMY_RADIUS):
print("Game Over!")
def is_collision(self, x1, y1, x2, y2, radius1, radius2):
distance_squared = (x1 - x2) 2 + (y1 - y2) 2
radius_sum_squared = (radius1 + radius2) ** 2
return distance_squared <= radius_sum_squaredПримечание: в реальной игре нужно аккуратно убирать пули, вышедшие за пределы экрана, чтобы не накапливать объекты и не утяжелять память.
Очки здоровья для врагов
Чтобы враги могли выдерживать несколько ударов, добавьте им параметр здоровья (HP). Это открывает возможности для стратегий и ощущения прогресса. В примере ниже задаётся константа ENEMY_HEALTH и уменьшается при столкновениях.
# Window dimensions
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
# Player attributes
PLAYER_RADIUS = 25
PLAYER_SPEED = 5
# Enemy attributes
ENEMY_RADIUS = 20
ENEMY_HEALTH = 100
class GameWindow(arcade.Window):
def __init__(self, width, height):
super().__init__(width, height)
arcade.set_background_color(arcade.color.WHITE)
self.player_x = width // 2
self.player_y = height // 2
self.enemy_x = width // 2
self.enemy_y = height - PLAYER_RADIUS
self.enemy_health = ENEMY_HEALTH
print(self.enemy_health)
def on_draw(self):
arcade.start_render()
arcade.draw_circle_filled(self.player_x,
self.player_y,
PLAYER_RADIUS,
arcade.color.BLUE)
if self.enemy_health > 0:
arcade.draw_circle_filled(self.enemy_x,
self.enemy_y,
ENEMY_RADIUS,
arcade.color.RED)
def update(self, delta_time):
if self.is_collision(self.player_x, self.player_y,
self.enemy_x, self.enemy_y,
PLAYER_RADIUS, ENEMY_RADIUS):
self.enemy_health -= 10
print(self.enemy_health) Вы можете отрисовать полоску здоровья (health bar) над врагом или выводить текстовую метку с текущим HP для наглядности.
Рекомендации по созданию врагов
Ниже собраны практические советы, которые помогут сделать врагов интереснее и корректнее реализуемыми.
Разнообразные атрибуты
Давайте у врагов разные параметры: скорость, размер, здоровье, урон. Это позволяет создавать уровни с растущей сложностью и вынуждает игрока менять тактику.
Уникальные поведения
Некоторые враги могут двигаться предсказуемо, другие — хаотично. Можно использовать простые состоянья: патруль, преследование, уклонение. Для сложного поведения подойдёт поведенческое дерево или конечный автомат.
Очки здоровья (HP)
HP позволяет врагам выдерживать удары и делает столкновения менее хаотичными. Различайте HP, чтобы разные типы врагов занимали разные роли в бою.
Важно: тестируйте параметры на реальном игровом уровне — числовые значения выглядят иначе при разных скоростях и размерах экрана.
Когда такой подход не подходит
- Массовые враги: если у вас сотни врагов, индивидуальные проверки столкновений и частые обновления приведут к просадкам FPS; используйте пространственные структуры (кубы/клетки, quad-tree) или физические движки.
- Сложная физика: если требуется столкновение по полигонам, отскоки, силы, используйте Pymunk/Box2D вместо ручных круговых коллизий.
- Сетевая игра: поведение на клиенте/сервере нужно синхронизировать и защищать от читов — авторитетность на сервере.
Альтернативные подходы
- Спрайты Arcade: используйте arcade.Sprite и arcade.SpriteList для автоматической батчевой отрисовки и встроенных способов проверки коллизий.
- Физические движки: Pymunk для точной физики с угловой скоростью и столкновениями.
- Поведенческие деревья / FSM: для сложной логики ИИ.
Мини‑методология для добавления нового типа врага
- Определите роль врага (нагнетатель, пушер, миньон, босс).
- Задайте базовые параметры: скорость, размер, HP, урон, радиус коллизии.
- Реализуйте визуал и спрайт(ы).
- Напишите update() с простым поведением.
- Добавьте тесты: столкновения, смерть, производительность.
- Итеративно балансируйте на реальном уровне.
Чек‑лист по ролям
Разработчик:
- Коллизии работают корректно на разных разрешениях.
- Пули очищаются после выхода с экрана.
- Нет утечек объектов при уничтожении врагов.
- Есть логирование ошибок.
Дизайнер:
- Поведение врага очевидно игроку (аудио/визуальная обратная связь).
- Параметры сложности протестированы.
- Враги вписываются в визуальный стиль.
QA:
- Тесты столкновений на разных скоростях.
- Тесты массового спауна врагов.
- Тесты сетевого синхрона (если применимо).
Критерии приёмки
- Враг отображается и двигается согласно логике.
- Столкновения детектируются при пересечении радиусов.
- Пули от врага наносят урон/срабатывают и удаляются корректно.
- Очки здоровья уменьшаются и влияют на отображение (health bar или текст).
- Производительность не падает при целевой нагрузке (см. требования проекта).
Факт‑бокс: ключевые числа из примеров
- Разрешение окна: 800×600 пикселей.
- Радиус игрока: 25.
- Скорость игрока: 5 (пикселей/обновление).
- Радиус врага: 20.
- HP врага (по умолчанию): 100.
- Параметры пуль: radius=5, speed=3, cooldown=60 кадров.
Краткое резюме
Добавление врагов — это не только отрисовка и проверка коллизий. Хорошо спроектированный враг имеет четкую роль, поведенческую модель и управляемые параметры. Используйте спрайты и списки объектов для производительности, выносите параметры в константы и тестируйте изменения в реальном геймплее.
Если вы хотите, можно адаптировать примеры к спрайтам arcade.Sprite, добавить полоски HP и реализовать поведение через FSM — напишите, какой вариант вам интересен, и я подготовлю доработанный пример с пояснениями.
Похожие материалы
RDP: полный гид по настройке и безопасности
Android как клавиатура и трекпад для Windows
Советы и приёмы для работы с PDF
Calibration в Lightroom Classic: как и когда использовать
Отключить Siri Suggestions на iPhone