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

Добавление случайно движущихся объектов в игры на Python Arcade

4 min read Game Dev Обновлено 03 Jan 2026
Случайно движущиеся объекты в Python Arcade
Случайно движущиеся объекты в Python Arcade

Введение

Случайно движущиеся объекты добавляют в игру элемент непредсказуемости и увеличивают вовлечённость. Эта статья переводит пошаговый пример на Python с библиотекой Arcade и расширяет его практическими советами, альтернативами и проверками качества.

Мальчик играет на ПК в наушниках с контроллером

Требования

  • Python 3.7+
  • pip
  • Библиотека arcade

Установка arcade:

pip install arcade

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

Быстрый старт — простая игра с одним игроком

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

import arcade  
  
SCREEN_WIDTH = 800  
SCREEN_HEIGHT = 600  
PLAYER_RADIUS = 15  
  
class MyGame(arcade.Window):  
    def __init__(self, width, height):  
        super().__init__(width, height)  
        arcade.set_background_color(arcade.color.WHITE)  
  
        self.player_x = SCREEN_WIDTH // 2  
        self.player_y = PLAYER_RADIUS + 10  
  
    def on_draw(self):  
        arcade.start_render()  
        arcade.draw_circle_filled(self.player_x, self.player_y, PLAYER_RADIUS, arcade.color.BLUE)  
  
    def update(self, delta_time):  
        pass  
  
    def on_key_press(self, key, modifiers):  
        if key == arcade.key.LEFT:  
            self.player_x -= 5  
        elif key == arcade.key.RIGHT:  
            self.player_x += 5  
  
if __name__ == "__main__":  
    game = MyGame(SCREEN_WIDTH, SCREEN_HEIGHT)  
    arcade.run()

Добавление нескольких объектов

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

import arcade  
import random  
  
SCREEN_WIDTH = 800  
SCREEN_HEIGHT = 600  
PLAYER_RADIUS = 15  
OBJECT_RADIUS = 10  
NUM_OBJECTS = 10  
  
class MyGame(arcade.Window):  
    def __init__(self, width, height):  
        super().__init__(width, height)  
        arcade.set_background_color(arcade.color.WHITE)  
  
        self.player_x = SCREEN_WIDTH // 2  
        self.player_y = PLAYER_RADIUS + 10  
  
        self.objects = []  
        for _ in range(NUM_OBJECTS):  
            x = random.randint(0, SCREEN_WIDTH)  
            y = random.randint(0, SCREEN_HEIGHT)  
            self.objects.append((x, y))  
  
    def on_draw(self):  
        arcade.start_render()  
        arcade.draw_circle_filled(self.player_x, self.player_y, PLAYER_RADIUS, arcade.color.BLUE)  
  
        for obj in self.objects:  
            x, y = obj  
            arcade.draw_circle_filled(x, y, OBJECT_RADIUS, arcade.color.RED)  
  
    def update(self, delta_time):  
        pass  
  
    def on_key_press(self, key, modifiers):  
        if key == arcade.key.LEFT:  
            self.player_x -= 5  
        elif key == arcade.key.RIGHT:  
            self.player_x += 5  
  
if __name__ == "__main__":  
    game = MyGame(SCREEN_WIDTH, SCREEN_HEIGHT)  
    arcade.run()

Ниже — пример вывода изображения с рандомным размещением объектов.

Несколько объектов, случайно размещённых вокруг игрока в Arcade

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

Чтобы объекты двигались случайно, обновляйте их позиции в методе update, добавляя случайные приращения dx и dy.

def update(self, delta_time):  
    for i in range(NUM_OBJECTS):  
        x, y = self.objects[i]  
        dx = random.randint(-5, 5)  
        dy = random.randint(-5, 5)  
        x += dx  
        y += dy  
        self.objects[i] = (x, y)

Объекты, движущиеся случайно вокруг игрока в Arcade

Примечание: при таком подходе объекты могут постепенно «убегать» за экран — добавьте ограничение по границам или телепорт при выходе.

Объекты движутся к игроку

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

import math

def update(self, delta_time):  
    for i in range(NUM_OBJECTS):  
        x, y = self.objects[i]  
        dx = self.player_x - x  
        dy = self.player_y - y  
        distance = math.sqrt(dx  2 + dy  2)  
        if distance == 0:  
            continue  
        dx /= distance  
        dy /= distance  
        x += dx * 3  
        y += dy * 3  
        self.objects[i] = (x, y)

Объекты, движущиеся к игроку в Arcade

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

Активация объектов по близости к игроку

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

def update(self, delta_time):  
    for i in range(NUM_OBJECTS):  
        x, y = self.objects[i]  
        dx = self.player_x - x  
        dy = self.player_y - y  
        distance = math.sqrt(dx  2 + dy  2)  
          
        if distance < 100:  
            dx /= distance  
            dy /= distance  
            x += dx * 3  
            y += dy * 3  
            self.objects[i] = (x, y)

Параметр радиуса (здесь 100) можно выносить в константу или в настройки уровня.

Детекция коллизий и взаимодействие

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

def update(self, delta_time):  
    for i in range(NUM_OBJECTS):  
        x, y = self.objects[i]  
        dx = self.player_x - x  
        dy = self.player_y - y  
        distance = math.sqrt(dx  2 + dy  2)  
          
        if distance < PLAYER_RADIUS + OBJECT_RADIUS:  
            # столкновение: удаляем объект и создаём новый в случайной позиции  
            self.objects.pop(i)  
            self.objects.append((random.randint(0, SCREEN_WIDTH), random.randint(0, SCREEN_HEIGHT)))  
              
        elif distance < 100:  
            dx /= distance  
            dy /= distance  
            x += dx * 3  
            y += dy * 3  
            self.objects[i] = (x, y)

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

Балансировка случайности

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

Ограничение максимальной скорости

Вводите MAX_SPEED и ограничивайте скорость компоненты dx и dy.

# в начале модули/константы
MAX_SPEED = 5

# в update
speed = 3
vx = dx * speed
vy = dy * speed
vx = max(min(vx, MAX_SPEED), -MAX_SPEED)
vy = max(min(vy, MAX_SPEED), -MAX_SPEED)
x += vx
y += vy

Контроль частоты спавна

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

import time  

class MyGame(arcade.Window):  
    def __init__(self, width, height):  
        super().__init__(width, height)  
        arcade.set_background_color(arcade.color.WHITE)  
  
        self.player_x = SCREEN_WIDTH // 2  
        self.player_y = PLAYER_RADIUS + 10  
  
        self.objects = []  
        self.last_spawn_time = time.time()  
  
    def update(self, delta_time):  
       # control the spawning rate here  
        if time.time() - self.last_spawn_time > SPAWN_DELAY:  
            if len(self.objects) < MAX_OBJECTS:  
                self.objects.append((random.randint(0, SCREEN_WIDTH), random.randint(0, SCREEN_HEIGHT)))  
                self.last_spawn_time = time.time()  

        for i in range(len(self.objects)):  
            x, y = self.objects[i]  
            dx = self.player_x - x  
            dy = self.player_y - y  
            distance = math.sqrt(dx  2 + dy  2)  

            if distance < PLAYER_RADIUS + OBJECT_RADIUS:  
                self.objects.pop(i)  
                self.objects.append((random.randint(0, SCREEN_WIDTH), random.randint(0, SCREEN_HEIGHT)))  
            elif distance < 100:  
                dx /= distance  
                dy /= distance  

                x += dx * 3  
                y += dy * 3  
                self.objects[i] = (x, y)

Настройте SPAWN_DELAY и MAX_OBJECTS для желаемого уровня сложности.

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

  • Контролируйте попадание за границы экрана: отражайте скорость или телепортируйте
  • Используйте arcade.Sprite и SpriteList для оптимизации при большом количестве объектов
  • Для естественного движения применяйте шум Перлина или алгоритмы «стирания» случайных векторов
  • Для более сложного поведения реализуйте состояния у объектов (спокойный, агрессивный, отступающий)

Альтернативные подходы

  1. Arcade SpriteList: храните объекты как Sprite с velocity и используйте встроенную коллизию.
  2. Steering behaviors: seek, flee, wander — паттерны поведения из игровой ИИ.
  3. Физические движки: pymunk для сложной физики столкновений и реалистичных отклонений.

Контрпримеры когда это не подходит

  • Повествовательные игры, где предсказуемость и режиссура важнее хаоса
  • Игры для малышей, где слишком динамичное окружение ухудшает восприятие
  • Сетевые игры, если поведение объектов отдельно не синхронизировано между клиентами

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

  • Дизайнер: выставить MAX_OBJECTS, SPAWN_DELAY, скорость и радиус активации
  • Разработчик: реализовать безопасную итерацию по спискам и границы поля
  • QA: проверить коллизии, утечки памяти, производительность при пиковых значениях

Тесты и критерии приёмки

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

  • Объекты корректно генерируются в пределах экрана
  • При столкновении объект исчезает и создаётся новый
  • Объекты не вызывают исключений при выходе за границы
  • Производительность устойчиво держится на целевом FPS при MAX_OBJECTS

Минимальные тесты:

  • Проверка спавна: объекты создаются через SPAWN_DELAY и не превосходят MAX_OBJECTS
  • Проверка коллизий: при пересечении радиусов выполняется логика столкновения
  • Проверка границ: объекты не создаются за пределами диапазона координат

Быстрые шаблоны и сниппеты

Пример использования SpriteList для движения и коллизий:

# упрощённый пример
player = arcade.Sprite("player.png", scale=0.5)
enemies = arcade.SpriteList()

for _ in range(NUM_OBJECTS):
    e = arcade.Sprite("enemy.png", scale=0.3)
    e.center_x = random.randint(0, SCREEN_WIDTH)
    e.center_y = random.randint(0, SCREEN_HEIGHT)
    enemies.append(e)

# в update: enemies.update(); проверка столкновений через arcade.check_for_collision_with_list(player, enemies)

Факты и числа

  • Ширина окна: 800
  • Высота окна: 600
  • Радиус игрока: 15
  • Радиус объекта: 10
  • Радиус активации по умолчанию в примерах: 100

Безопасность и производительность

  • При большом количестве объектов используйте SpriteList и batch-отрисовку
  • Ограничивайте частоту спавна и общее число объектов
  • Для серверной валидации поведения объектов синхронизируйте только необходимые параметры

Короткая версия для анонса

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

Резюме

  • Начните с простого списка координат или используйте SpriteList
  • Для приближения используйте нормализованный вектор и ограничьте скорость
  • Контролируйте спавн и количество объектов для стабильной производительности
  • Тестируйте коллизии, границы экрана и поведение при граничных значениях

Важно: при нормализации всегда проверяйте деление на ноль и аккуратно работайте с удалением элементов из коллекций.

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

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

Как скачать полноразмерный аватар Discord
Руководство

Как скачать полноразмерный аватар Discord

CSV в Node.js: fs и fast-csv — чтение и запись
Node.js

CSV в Node.js: fs и fast-csv — чтение и запись

Как увеличить экран на ПК — все способы
Инструкции

Как увеличить экран на ПК — все способы

Как найти человека в WhatsApp — быстро и просто
Мессенджеры

Как найти человека в WhatsApp — быстро и просто

Подсказки формул в Excel — руководство
Excel

Подсказки формул в Excel — руководство

Папка «Если меня нет»: подготовьте экстренный профиль
Безопасность

Папка «Если меня нет»: подготовьте экстренный профиль