Враги в PyGame: движение и поведение

Кратко о том, что нужно знать
- В PyGame враги обычно представлены как pygame.Rect или как объекты с позицией и скоростью.
- Для движения полезны векторы (pygame.math.Vector2) и нормализация направления.
- Частые паттерны: преследование, случайное блуждание, активация по радиусу, уклонение.
Создание простой игры
Создайте минимальную сцену, где игрок перемещается по экрану, а столкновение с врагом означает «смерть» игрока. Это база для проверки логики врагов.
Полный код можно поместить в репозиторий на GitHub для удобства совместной работы.
Начните с импорта PyGame и инициализации:
import pygame
pygame.init()Задайте экран и создайте объекты игрока и врага с помощью pygame.Rect():
# Set up the screen
screen = pygame.display.set_mode((800, 600))
# Set up the colors
black = (0, 0, 0)
white = (255, 255, 255)
# Set up the player rectangle and the enemy object
player = pygame.Rect(350, 500, 50, 50)
enemy = pygame.Rect(350, 0, 50, 50)Запустите главный цикл игры: обработка событий, передвижение игрока, проверка столкновений и отрисовка.
# Set up the game loop
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Fill the screen with white
screen.fill(white)
# Move the player rectangle
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
player.x -= 5
if keys[pygame.K_RIGHT]:
player.x += 5
if keys[pygame.K_UP]:
player.y -= 5
if keys[pygame.K_DOWN]:
player.y += 5
# Check for collision between player and enemy
if player.colliderect(enemy):
running = False
# Draw the player rectangle and the enemy object on the screen
pygame.draw.rect(screen, black, player)
pygame.draw.rect(screen, black, enemy)
# Update the screen
pygame.display.update()
# Quit the game
pygame.quit()Примечание: в этом коде движение игрока задано в пикселях за кадр. Для стабильного поведения на разных машинах используйте dt (delta time) или pygame.time.Clock().
Преследование игрока (направить врага к игроку)
Чтобы заставить врага идти к игроку, вычислите вектор направления и нормализуйте его. В примерах используется теорема Пифагора — расстояние в пикселях.
# Calculate the distance between the enemy and the player
distance_x = player.x - enemy.x
distance_y = player.y - enemy.y
distance = (distance_x 2 + distance_y 2) ** 0.5
# Move the enemy toward the player
speed = 2
if distance != 0:
enemy.x += speed * distance_x / distance
enemy.y += speed * distance_y / distanceСоветы по улучшению:
- Замените расчёты на pygame.math.Vector2 для читаемости и точности.
- Ограничьте максимальную скорость, примените плавное ускорение/торможение.
- Проверяйте границы экрана, чтобы враг не вышел за пределы.
Случайное движение врага
Для простого нецелевого поведения выбирают случайное направление. Это сделает поведение менее предсказуемым.
import random
# Move the enemy randomly on the screen
direction = random.choice(['left', 'right', 'up', 'down'])
if direction == 'left':
enemy.x -= 5
elif direction == 'right':
enemy.x += 5
elif direction == 'up':
enemy.y -= 5
elif direction == 'down':
enemy.y += 5Улучшения:
- Меняйте направление не каждый кадр, а каждые N кадров или через таймер.
- Смешивайте случайность с состояниями (например: патруль → агрессия).
Движение по близости (проактивация)
Если нужно, чтобы враг активировался только рядом с игроком, сравните расстояние с порогом в пикселях (например, 300 пикселей).
# Move the enemy toward the player if the player is close
speed = 2
if distance < 300:
if distance != 0:
enemy.x += speed * distance_x / distance
enemy.y += speed * distance_y / distanceПрактическое применение: использование проактивации экономит ресурсы и позволяет создавать «зоны опасности».
Враг уклоняется от игрока
Уклонение реализуется через движение по вектору, перпендикулярному направлению на игрока. Это делает поведение более хитрым и живым.
speed = 2
if distance < 400:
if distance != 0:
# Calculate the unit vector toward the player
unit_vector_x = distance_x / distance
unit_vector_y = distance_y / distance
# Calculate the perpendicular vector
perpendicular_vector_x = -unit_vector_y
perpendicular_vector_y = unit_vector_x
# Calculate the dot product of the perpendicular vector and the
# unit vector
dot_product = perpendicular_vector_x * unit_vector_x
+ perpendicular_vector_y * unit_vector_y
# Move the enemy perpendicular to the unit vector
if dot_product > 0:
enemy.x += speed * perpendicular_vector_x
enemy.y += speed * perpendicular_vector_y
else:
enemy.x -= speed * perpendicular_vector_x
enemy.y -= speed * perpendicular_vector_yЗамечание: такой подход даёт эффект «изворотливого» врага, но не гарантирует обход препятствий. Для уклонения с учётом коллизий используйте навигацию по сетке или систему путь-избежания.
Добавление дополнительных фич: несколько врагов, препятствия, таймер
Пример расширения: несколько врагов, препятствия и стабилизация FPS через Clock.
# Add multiple enemies that move randomly on the screen
enemies = []
for i in range(5):
enemy = pygame.Rect(random.randint(0, 750), random.randint(0, 550), 50,
50)
enemies.append(enemy)
# Add obstacles that the player needs to avoid
obstacle = pygame.Rect(200, 250, 50, 50)
# Set up the game loop
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Fill the screen with white
screen.fill(white)
# Move the player rectangle
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
player.x -= 5
if keys[pygame.K_RIGHT]:
player.x += 5
if keys[pygame.K_UP]:
player.y -= 5
if keys[pygame.K_DOWN]:
player.y += 5
# Move the enemies randomly on the screen
for enemy in enemies:
direction = random.choice(['left', 'right', 'up', 'down'])
if direction == 'left':
enemy.x -= 5
elif direction == 'right':
enemy.x += 5
elif direction == 'up':
enemy.y -= 5
elif direction == 'down':
enemy.y += 5
# Check for collision between player and enemy
if player.colliderect(enemy):
running = False
# Draw the player rectangle, the enemy objects, and the obstacle on
# the screen
pygame.draw.rect(screen, black, player)
for enemy in enemies:
pygame.draw.rect(screen, black, enemy)
pygame.draw.rect(screen, black, obstacle)
# Update the screen
pygame.display.update()
# Set the frame rate of the game
clock.tick(60)
# Quit the game
pygame.quit()Совет: clock.tick(60) устанавливает целевой FPS в 60 кадров в секунду — распространённое значение для плавной анимации.
Important: всегда проверяйте столкновения с препятствиями и не позволяйте персонажам выходить за пределы экрана. Это предотвратит баги и «залипание» объектов за пределами игрового поля.
Практические советы и шаблоны проектирования
- Используйте состояния (Finite State Machine) для врагов: “патруль → преследование → уклонение → атака”. Так легче управлять логикой и отлаживать поведение.
- Для сложной навигации используйте A* по навигационной сетке или навмеш, а не только векторные расчёты.
- Для плавного движения применяйте интерполяцию и ускорение (velocity, acceleration).
- Для оптимизации — активируйте врагов по радиусу видимости, чтобы не обновлять поведение слишком большого числа сущностей.
- Для физики и коллизий изучите pygame.sprite.Group и встроенные функции пересечений.
Мини-методология внедрения врагов (пошагово)
- Прототип: реализуйте один враг с простым преследованием и проверкой столкновений.
- Тестирование: проверьте поведение при разных скоростях и размерах экрана.
- Состояния: добавьте FSM (патруль, агрессия, уклонение).
- Масштабирование: добавьте несколько врагов, оптимизируйте обновления (активация по радиусу).
- Полировка: анимация, эффекты, звуковые сигналы при обнаружении игрока.
Чек-лист ролей
- Разработчик:
- Реализовать базовую механику движения и коллизий.
- Добавить dt и ограничение скорости.
- Обработать границы экрана и препятствия.
- Дизайнер уровня:
- Установить зоны активации и позиции патрулей.
- Настроить скорости и дистанции тревоги.
- Тестировщик:
- Проверить, что враги не застревают в геометрии.
- Проверить производительность при большом количестве врагов.
Когда эти подходы не подходят (контрпримеры)
- Если нужна реалистичная навигация в сложной среде со множеством препятствий — векторное преследование не даст корректных путей; нужен A* или NavMesh.
- Для больших массовых боёв требуется оптимизация через LOD, кластеры или потоковую логику, иначе игра потеряет FPS.
Мини-словарь (1 строка)
- FSM: конечный автомат состояний, используется для управления поведением.
- A*: алгоритм поиска кратчайшего пути на сетке/графе.
- Vector2: класс векторов в pygame для простых векторных операций.
Критерии приёмки
- Враг преследует игрока, когда тот в пределах заданного радиуса (например, 300 пикселей).
- Враг не выходит за границы экрана и корректно реагирует на препятствия.
- Количество врагов на экране соответствует требованиям производительности (профилирование).
FAQ
Q: Как лучше хранить состояние врага?
A: Через атрибут state в объекте врага (строка/enum) и обработчик переходов.
Q: Нужно ли нормализовать векторы движения?
A: Да — нормализация даёт равномерную скорость независимо от расстояния.
Q: Как избежать рывков при разной частоте кадров?
A: Передавайте dt (delta time) в расчёты перемещения: pos += velocity * dt.
Итог
Добавление врагов с разными типами движения резко повышает интересность игры. Начните с простого преследования и постепенно вводите состояния, навигацию и оптимизацию. Тестируйте на разных разрешениях и профилируйте производительность при увеличении числа врагов.
Дополнительные шаги: мигрируйте расчёты на pygame.math.Vector2, внедрите A* для сложных уровней и используйте FSM для управления поведением.
Похожие материалы
RDP: полный гид по настройке и безопасности
Android как клавиатура и трекпад для Windows
Советы и приёмы для работы с PDF
Calibration в Lightroom Classic: как и когда использовать
Отключить Siri Suggestions на iPhone