Гид по технологиям

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

5 min read Game Dev Обновлено 04 Jan 2026
Движение врагов в PyGame: руководства и примеры
Движение врагов в 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: всегда проверяйте столкновения с препятствиями и не позволяйте персонажам выходить за пределы экрана. Это предотвратит баги и «залипание» объектов за пределами игрового поля.

Практические советы и шаблоны проектирования

  1. Используйте состояния (Finite State Machine) для врагов: “патруль → преследование → уклонение → атака”. Так легче управлять логикой и отлаживать поведение.
  2. Для сложной навигации используйте A* по навигационной сетке или навмеш, а не только векторные расчёты.
  3. Для плавного движения применяйте интерполяцию и ускорение (velocity, acceleration).
  4. Для оптимизации — активируйте врагов по радиусу видимости, чтобы не обновлять поведение слишком большого числа сущностей.
  5. Для физики и коллизий изучите pygame.sprite.Group и встроенные функции пересечений.

Мини-методология внедрения врагов (пошагово)

  1. Прототип: реализуйте один враг с простым преследованием и проверкой столкновений.
  2. Тестирование: проверьте поведение при разных скоростях и размерах экрана.
  3. Состояния: добавьте FSM (патруль, агрессия, уклонение).
  4. Масштабирование: добавьте несколько врагов, оптимизируйте обновления (активация по радиусу).
  5. Полировка: анимация, эффекты, звуковые сигналы при обнаружении игрока.

Чек-лист ролей

  • Разработчик:
    • Реализовать базовую механику движения и коллизий.
    • Добавить 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 для управления поведением.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

RDP: полный гид по настройке и безопасности
Инфраструктура

RDP: полный гид по настройке и безопасности

Android как клавиатура и трекпад для Windows
Гайды

Android как клавиатура и трекпад для Windows

Советы и приёмы для работы с PDF
Документы

Советы и приёмы для работы с PDF

Calibration в Lightroom Classic: как и когда использовать
Фото

Calibration в Lightroom Classic: как и когда использовать

Отключить Siri Suggestions на iPhone
iOS

Отключить Siri Suggestions на iPhone

Рисование таблиц в Microsoft Word — руководство
Office

Рисование таблиц в Microsoft Word — руководство