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

Добавление случайно двигающихся объектов в Pygame

6 min read Разработка игр Обновлено 26 Dec 2025
Случайно двигающиеся объекты в Pygame
Случайно двигающиеся объекты в Pygame

Игрок играет с контроллером

Введение

Pygame — популярная библиотека Python для разработки 2D-игр. Добавление случайно двигающихся объектов оживляет сцену: это могут быть препятствия, враги, бонусы или предметы окружения. В статье показано несколько пошаговых подходов: от простого горизонтального движения до алгоритмов преследования и активации при приближении игрока.

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

Создание простой игры

Сначала настраиваем окно Pygame, добавляем игрока и платформы, реализуем базовое управление клавишами. Создайте файл simple-game.py и поместите туда начальный каркас. Ниже — минимальный рабочий пример, который можно расширять.

# simple-game.py
import pygame
import random
import math

pygame.init()

screen_width, screen_height = 800, 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption('Simple Pygame')
clock = pygame.time.Clock()

WHITE = (255, 255, 255)
BLACK = (0, 0, 0)

# Игрок
player_width, player_height = 40, 60
player_x = screen_width // 2
player_y = screen_height - player_height - 50
player_speed = 5

running = True

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]:
        player_x -= player_speed
    if keys[pygame.K_RIGHT]:
        player_x += player_speed

    screen.fill(BLACK)
    pygame.draw.rect(screen, WHITE, (player_x, player_y, player_width, player_height))

    pygame.display.update()
    clock.tick(60)

pygame.quit()

Игровой объект игрока и две платформы

Добавление нескольких двигающихся объектов

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

# Настройки объектов
object_width, object_height = 30, 30
object_speed_range = (2, 7)
objects = []

def create_random_object():
    return {
        'x': random.randint(0, screen_width - object_width),
        'y': random.randint(0, screen_height - object_height),
        'speed': random.randint(*object_speed_range)
    }

for _ in range(5):
    objects.append(create_random_object())

def draw_object(obj):
    obj_dim = (int(obj['x']), int(obj['y']), object_width, object_height)
    pygame.draw.rect(screen, WHITE, obj_dim)

# В основном цикле, после отрисовки игрока
for obj in objects:
    obj['x'] += obj['speed']
    if obj['x'] > screen_width:
        obj['x'] = -object_width
    draw_object(obj)

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

Несколько случайно двигающихся объектов с игроком и платформой

Примечания

  • Размеры и скорость заданы в пикселях и пикселях/кадр соответственно.
  • Если скорость дробная (например при использовании векторной физики), приводите координаты к int при отрисовке.

Алгоритм случайного движения

Чтобы объекты не двигались строго прямо, можно время от времени менять направление. Ниже — простая функция, которая с небольшой вероятностью инвертирует скорость.

# Случайное изменение направления
import random

def update_random_movement(obj):
    # С вероятностью 1% меняем направление
    if random.random() < 0.01:
        obj['speed'] = -obj['speed']

Вставьте update_random_movement(obj) в основной цикл для каждого объекта перед отрисовкой.

Движение объектов в сторону игрока

Чтобы объекты могли преследовать игрока, используйте вектор направления и функции math.cos/math.sin с углом, посчитанным через atan2. Это позволяет получать плавное движение в сторону цели.

import math

def move_towards_player(obj, player_x, player_y):
    player_center_x = player_x + player_width / 2
    player_center_y = player_y + player_height / 2
    object_center_x = obj['x'] + object_width / 2
    object_center_y = obj['y'] + object_height / 2

    dx = player_center_x - object_center_x
    dy = player_center_y - object_center_y

    angle = math.atan2(dy, dx)
    speed = obj.get('speed', 3)
    # Можно использовать дробные координаты для более плавного движения
    obj['x'] += speed * math.cos(angle)
    obj['y'] += speed * math.sin(angle)

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

Активация движения при приближении игрока

Чтобы не загружать сцену сразу всеми объектами, можно включать их движение только когда игрок подходит на определённое расстояние.

surrounding_distance = 150

def should_start_moving(obj, player_x, player_y):
    dx = abs(obj['x'] - player_x)
    dy = abs(obj['y'] - player_y)
    return dx < surrounding_distance or dy < surrounding_distance

# В цикле
for obj in objects:
    if should_start_moving(obj, player_x, player_y):
        obj['x'] += obj['speed']
        if obj['x'] > screen_width:
            obj['x'] = -object_width
        update_random_movement(obj)
        move_towards_player(obj, player_x, player_y)
    draw_object(obj)

Такой подход экономит ресурсы и создаёт эффект «оживающего» окружения.

Обнаружение столкновений и взаимодействие

Одна из распространённых механик — удалять объект при столкновении с игроком или, наоборот, наносить урон. Ниже — базовая функция проверки пересечения AABB (Axis-Aligned Bounding Box).

def is_collision(obj, player_x, player_y):
    condition1 = player_x + player_width > obj['x']
    condition2 = player_x < obj['x'] + object_width
    condition3 = player_y + player_height > obj['y']
    condition4 = player_y < obj['y'] + object_height
    return condition1 and condition2 and condition3 and condition4

# В цикле
for obj in objects[:]:  # итерируем по копии списка при потенциальном удалении
    if should_start_moving(obj, player_x, player_y):
        obj['x'] += obj['speed']
        if obj['x'] > screen_width:
            obj['x'] = -object_width
        update_random_movement(obj)
        move_towards_player(obj, player_x, player_y)

    if is_collision(obj, player_x, player_y):
        # Пример: убрать объект и начислить очки
        objects.remove(obj)
    else:
        draw_object(obj)

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

Альтернативный подход: pygame.sprite.Sprite и группы

Для больших сцен рекомендуется использовать встроенную систему Sprite и Group. Это упрощает коллизии (pygame.sprite.spritecollide) и оптимизирует отрисовку.

Пример упрощённого Sprite:

class MovingObject(pygame.sprite.Sprite):
    def __init__(self, x, y, speed):
        super().__init__()
        self.image = pygame.Surface((object_width, object_height))
        self.image.fill(WHITE)
        self.rect = self.image.get_rect(topleft=(x, y))
        self.speed = speed

    def update(self, player_rect=None):
        # Пример: простое движение и преследование
        self.rect.x += int(self.speed)
        if player_rect and self.rect.colliderect(player_rect):
            self.kill()

Группы позволяют вызывать group.update() и group.draw(screen) и использовать оптимизацию пакетной отрисовки.

Включение дополнительных фич

Ниже перечислены идеи и практические советы для дальнейшего развития механики случайно двигающихся объектов.

Система очков и прогрессия

  • Назначайте разное число очков за разные объекты по сложности или редкости.
  • Плавно увеличивайте сложность: увеличивайте число объектов, диапазон скоростей или уменьшайте расстояние активации.
  • Не делайте темп увеличения сложности резким — используйте кривую роста (линейную или экспоненциальную с малыми коэффициентами).

Пауэр-апы и бонусы

  • Создайте объекты, дающие временные эффекты: ускорение, неуязвимость, «заморозку» врагов.
  • Храните состояние эффектов со временем истечения (таймер в кадрах или секундах).

Поведение врагов и простая AI

  • Реализуйте состояния: патруль, преследование, отступление.
  • Используйте конечные автоматы (FSM) для переключения между поведениями.
  • Комбинируйте поведение: патруль почти всегда, преследование — при близком расстоянии.

Коллекционные предметы и награды

  • Собираемые предметы можно использовать как валюту для разблокировки уровней или косметики.
  • Обдумайте баланс: редкость предметов и их ценность должны мотивировать, но не ломать игру.

Лучшие практики

Балансировка сложности

  • Тестируйте на нескольких уровнях мастерства.
  • Для новых игроков используйте меньшую скорость и меньше врагов.
  • Добавьте динамическую регулировку сложности (например, при длительной неудаче уменьшайте сложность).

Оптимизация и производительность

  • Используйте pygame.sprite.Group для отрисовки и обновления.
  • Сведите к минимуму allocation/GC в основном цикле (не создавать объекты каждый кадр).
  • Ограничьте сложность вычислений: избегайте тяжёлых trig-функций для большого количества объектов; используйте предвычисленные векторы когда возможно.

Тестирование и доводка

  • Прогоняйте стресс-тесты с большим количеством объектов.
  • Тестируйте столкновения и сценарии удаления объектов.
  • Собирайте фидбек от игроков и корректируйте параметры.

Контролируемая случайность

  • Вместо чистого random используйте семена для воспроизводимости при тестировании.
  • Определите допустимые диапазоны параметров для каждого типа объекта.

Практическая мини-методология внедрения

  1. Начните с простого поведения (горизонтальная линейная скорость).
  2. Добавьте случайную инверсию направления для вариативности.
  3. Введите активацию в зоне (~150 px) для экономии ресурсов.
  4. Добавьте преследование через atan2 для опасных врагов.
  5. Переведите объекты в систему Sprite/Group для оптимизации.
  6. Тестируйте и регулируйте параметры (скорости, радиусы, частоты изменения).

Критерии приёмки

  • Все объекты корректно отрисовываются и не «зависают» вне экрана.
  • Объекты активируются только при приближении (если включено).
  • Столкновения с игроком детектируются правильно и вызывают ожидаемое поведение (удаление, урон, бонус).
  • Игра держит целевой FPS (обычно 60) при ожидаемом количестве объектов на целевых платформах.
  • Поведение объектов отвечает требованиям дизайна (баланс сложности).

Роль‑ориентированные контрольные списки

Разработчик:

  • Реализовать объекты и их логику в отдельных классах/модулях.
  • Перевести на Sprite/Group при росте числа объектов.
  • Обеспечить корректный цикл удаления объектов.

Дизайнер:

  • Установить скорости, размеры и радиусы активации.
  • Разработать набор состояний поведения для врагов.

Тестер:

  • Провести стресс‑тесты с большим количеством объектов.
  • Проверить коллизии в границах и на краях экранов.
  • Проверить воспроизводимость при фиксированном seed.

Факты и ключевые значения

  • Размер объекта в примерах: 30×30 пикселей.
  • Диапазон скорости: 2–7 (пикселей/кадр в примерах).
  • Частота обновления в примерах: 60 FPS.
  • Радиус активации по умолчанию: 150 пикселей.

Отладка и распространённые ошибки

  • Удаление элементов из списка во время итерации вызывает пропуски: итерируйтесь по копии списка или используйте индексы.
  • Использование int для позиций делает движение «рваными» при малых скоростях; храните внутренние координаты в float, а отрисовку делайте с int().
  • Слишком частые триг-функции в большом количестве объектов приводят к проседанию FPS.

Примеры тест-кейсов

  • При появлении 100 объектов игра должна сохранять >30 FPS на целевой машине.
  • Объект, вышедший за правый край, должен появиться с левого края корректно.
  • При пересечении границ коллизий объект удаляется и очки начисляются.

Заключение

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

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

Дополнительные ресурсы: используйте официальную документацию Pygame и репозиторий с лицензией MIT для примеров и шаблонов.

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

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

Компьютер не включается — шаги по устранению
Ремонт ПК

Компьютер не включается — шаги по устранению

Проверка текста ChatGPT через Bing AI
Искусственный интеллект

Проверка текста ChatGPT через Bing AI

Научите ChatGPT вашему стилю письма
Написание

Научите ChatGPT вашему стилю письма

Картинка в картинке на iPhone и iPad — настройка и советы
Мобильные устройства

Картинка в картинке на iPhone и iPad — настройка и советы

Как писать, чтобы выделиться среди AI
Копирайтинг

Как писать, чтобы выделиться среди AI

Удаление и скрытие значков на рабочем столе Windows
Windows

Удаление и скрытие значков на рабочем столе Windows