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

Создание врагов в Godot для 2D‑игр

7 min read Разработка игр Обновлено 11 Apr 2026
Создание врагов в Godot для 2D‑игр
Создание врагов в Godot для 2D‑игр

Враги — ключевой элемент многих игр: они задают вызов, формируют ритм и делают прохождение запоминающимся. Godot с его простым интерфейсом и GDScript позволяет быстро прототипировать поведения врагов и масштабировать их в более сложные системы.

Что вы получите из этой статьи

  • Полная структура и готовые скрипты для нескольких типов врагов (статический, преследующий, стрелок, случайный)
  • Исправления и уточнения для распространённых ошибок (например, направление выстрела)
  • Практический плейбук, чеклисты ролей и критерии приёмки
  • Альтернативные подходы, матрица совместимости и рекомендации по балансу

Настройка проекта Godot

Прежде чем переходить к созданию врагов, настройте базовую 2D‑структуру в Godot.

  1. Создайте новый 2D‑проект.
  2. В главной сцене добавьте узел KinematicBody2D и назовите его Player.
  3. Внутри Player добавьте CollisionShape2D с прямоугольной формой для хитбокса и Sprite для визуализации персонажа.

Исходный код, использованный в статье, доступен в репозитории на GitHub и распространяется под MIT‑лицензией.

Привяжите к узлу Player этот скрипт для базового передвижения (GDScript):

extends KinematicBody2D  
  
const SPEED = 200  
  
func _physics_process(delta):  
    var motion = Vector2.ZERO  
  
    if Input.is_action_pressed("ui_right"):  
        motion.x += SPEED  
  
    if Input.is_action_pressed("ui_left"):  
        motion.x -= SPEED  
  
    if Input.is_action_pressed("ui_down"):  
        motion.y += SPEED  
  
    if Input.is_action_pressed("ui_up"):  
        motion.y -= SPEED  
  
    motion = move_and_slide(motion)

С этим кодом игрок может передвигаться в четырёх направлениях с помощью стрелок или WASD.

простая сцена с узлом игрока

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

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

  1. Создайте новую сцену.
  2. Добавьте StaticBody2D и назовите его Enemy.
  3. Внутри добавьте CollisionShape2D с круговой формой и Sprite для визуала.

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

Враг‑преследователь

Враги, которые следуют за игроком, создают постоянное давление и ощущение опасности.

Создайте сцену с KinematicBody2D, назовите её FollowEnemy, добавьте CollisionShape2D. Привяжите код:

extends KinematicBody2D  
  
const SPEED = 100  
  
func _physics_process(delta):  
    var player = get_parent().get_node("Player")  
    var player_position = player.global_position  
    var enemy_position = global_position  
    var direction = player_position - enemy_position  
    direction = direction.normalized()  
  
    var motion = direction * SPEED * delta  
    move_and_collide(motion)

Комментарий: этот подход предполагает, что Player — соседний узел в иерархии. В более крупных проектах используйте сигналы, автозагрузки или слежение через группу (groups) для поиска игрока.

узел врага, преследующего игрока

Добавление пуль у врагов

Стрелки и стрелки‑враги добавляют дистанционную угрозу. Для этого создаётся отдельная сцена пули и логика её движения.

Создайте Bullet.tscn с KinematicBody2D и привяжите к нему Bullet.gd со следующим кодом:

extends KinematicBody2D  
  
const BULLET_SPEED = 300  
var bullet_direction = Vector2.ZERO  
  
func _physics_process(delta):  
    var motion = bullet_direction * BULLET_SPEED * delta  
    move_and_collide(motion)  
  
func set_direction(direction):  
    bullet_direction = direction.normalized()

Теперь создадим врага‑стрелка. Внутри сцены ShootingEnemy (KinematicBody2D) добавьте CollisionShape2D и привяжите код:

extends KinematicBody2D  
  
const SPEED = 100  
const SHOOT_DELAY = 1.5  
var shoot_timer = SHOOT_DELAY  
  
# Import the Bullet scene  
const BulletScene = preload("res://Bullet.tscn")  
  
func _physics_process(delta):  
  
    # Shooting logic  
    shoot_timer -= delta  
  
    if shoot_timer <= 0:  
        shoot_timer = SHOOT_DELAY  
        var bullet_instance = BulletScene.instance()   
        bullet_instance.global_position = global_position  
        # Вычисляем направление к игроку  
        var player = get_parent().get_node("Player")  
        var direction = (player.global_position - global_position).normalized()  
        bullet_instance.set_direction(direction)   
        get_parent().add_child(bullet_instance)

Важно: в исходном фрагменте использовалась переменная direction без объявления — это частая ошибка. В примере выше мы явно вычисляем направление к игроку и передаём его в пулю.

сцена врага и игрока с пулей

Случайно движущийся враг

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

Создайте RandomEnemy (KinematicBody2D) и используйте этот скрипт:

extends KinematicBody2D  
  
const MOVE_SPEED = 100  
const MOVE_INTERVAL_MIN = 1.0  
const MOVE_INTERVAL_MAX = 3.0  
  
var move_timer = 0.0  
var move_interval = 0.0  
var move_direction = Vector2.ZERO  
  
func _ready():  
    choose_new_direction()  
  
func choose_new_direction():  
    move_interval = rand_range(MOVE_INTERVAL_MIN, MOVE_INTERVAL_MAX)  
    move_timer = move_interval  
    move_direction = Vector2(randf(), randf()).normalized()  
  
func _physics_process(delta):  
    move_timer -= delta  
  
    if move_timer <= 0.0:  
        choose_new_direction()  
  
    var motion = move_direction * MOVE_SPEED * delta  
    move_and_collide(motion)

Совет: вместо Vector2(randf(), randf()) можно использовать рандомизацию по кругу, чтобы получить равномерно распределённые направления: Vector2(cos(angle), sin(angle)).

Дополнительные возможности врагов

Добавляя разнообразие врагов, вы повышаете реиграбельность и глубину игры. Вот несколько направлений развития:

Боссы

Боссы — крупные, многофазные враги с уникальными механиками. Для реализации используйте подстадии (states) и чёткие переходы между фазами.

Динамическая спавн‑система

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

Адаптация к окружению

Враги, которые умеют летать, плавать или карабкаться по стенам, расширяют дизайн уровней. Разделите поведение по способностьям (traits) и комбинируйте их.

Слабости и резисты

Присвойте врагам уязвимости к определённым видам урона. Это стимулирует эксперименты и тактическое мышление.

Вариации поведения

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

Лучшие практики при создании врагов

Чёткая визуальная коммуникация

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

Баланс сложности

Вводите сложности постепенно и избегайте резких скачков. Тестируйте на игроках разного уровня навыков.

Избегайте нечестных попаданий

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

Плейтестинг и итерации

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

Звуковое сопровождение

Добавьте звуки ударов, шагов и выстрелов — они усиливают обратную связь и помогают игроку ориентироваться.

Практический плейбук: как ввести нового врага в игру (шаблон)

  1. Концепция: опишите роль врага, его слабости, силы и желаемое поведение.
  2. Арт и звук: нарисуйте силуэт, создайте спрайты и FX, подготовьте звуковые файлы.
  3. Прототип: реализуйте базовый узел (KinematicBody2D/StaticBody2D/Area2D) и простую логику.
  4. Интеграция: добавьте врага в сцену, обеспечьте корректные коллайдеры и слои коллизий.
  5. Баланс: настройте параметры (здоровье, урон, скорость) и проведите тесты.
  6. Тестирование: прогоните чеклист QA и исправьте найденные баги.
  7. Релиз: внесите в менеджер спавна и документируйте изменения в логах.

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

Дизайнер:

  • Описать поведение и роль в уровне
  • Составить сценарии взаимодействий с игроком

Программист:

  • Создать узел и скрипт
  • Обеспечить корректную регистрацию столкновений и удаления объектов
  • Добавить варианты настройки через экспортируемые переменные

Артист:

  • Сделать спрайты и анимации
  • Подготовить VFX для атак и попаданий

QA:

  • Проверить попадания и хитбоксы
  • Протестировать на всех доступных уровнях сложности

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

  • Враг корректно спавнится и удаляется без утечек памяти
  • Поведение соответствует описанию дизайна
  • Хитбоксы совпадают с визуалом на 90%+ (визуально и технически адекватны)
  • Отсутствие блокировок игрока из‑за поведения врага
  • Логирование критических событий (смерть, баги) работает

Тестовые сценарии

  • Статический враг: игрок должен получать урон при контакте и не при отдалении
  • Враг‑преследователь: тест на зацикливание и фризы при удалении игрока
  • Враг‑стрелок: пули должны корректно удаляться при выходе за пределы сцены
  • Случайный враг: проверить, что движение не приводит к «залипанию» на границе карты

Когда подходы не работают (примеры неудач)

  • Простая логика преследования без учёта препятствий ведёт к застреванию у стен.
  • Частые инстансы пулей без пуллинга/пулинга объектов создают нагрузку на GC и ухудшают FPS.
  • Слишком высокая вариативность поведения без явной структуированной логики затрудняет баланс.

Альтернативы и расширения

  • Area2D для триггерных врагов (патруль, зона обнаружения)
  • RigidBody2D с контролируемой силой для физически достоверных реакций
  • Behaviour Trees/Finite State Machines для сложных AI
  • Использование Navigation2D и обхода препятствий (A* или NavigationAgent2D)

Ментальные модели и эвристики

  • Разделяйте «врага» на данные (параметры), представление (спрайт/анимации) и поведение (скрипт).
  • Думайте о враге как о системе ввода‑вывода: он принимает ввод (игрок, окружение) и выдаёт выход (движение, атака).
  • Превоздержание: проще добавить поведение, чем убира́ть его; делайте фичи модульными.

Матрица сравнения типов врагов (упрощённо)

  • Static: лёгкий для реализации, низкая нагрузка, подходит для окружения.
  • Follow: средняя степень сложности, требует контроля пути и избегания застревания.
  • Shooting: требует spawn/pool для пуль, более затратен по логике.
  • Random: повышает разнообразие, может требовать дополнительных ограничений по зонам.

Snippets — шорт‑читы и шаблоны

Пул объектов (простая реализация):

# Простой пул для повторного использования пуль
var pool = []
func get_bullet():
    for b in pool:
        if not b.get_parent():
            return b
    var b = BulletScene.instance()
    pool.append(b)
    return b

Пример безопасного удаления пули:

func _on_visibility_screen_exited():
    queue_free()

План реагирования на инциденты (rollback)

Если новая механика врагов критически ломает баланс или вызывает утечки:

  1. Откатить спавн или отключить новый тип через feature toggle.
  2. Заблокировать спавн в продакшн‑сценах.
  3. Собрать логи: частота спавна, использование памяти, стектрейсы.
  4. Произвести исправления в тестовой ветке и прогнать регрессионные тесты.

Риск‑матрица и смягчения

  • Перегрузка CPU из‑за большого числа пуль — использовать пул объектов и лимит на активные пули.
  • Застревание у стен — добавить обход через Navigation2D или простой отталкивающий вектор при коллизии.
  • Нечестный урон — настроить визуальные и аудио предупреждения, откорректировать хитбоксы.

Совместимость и миграция

При переходе с Godot 3.x на 4.x проверьте изменения в API (например, NavigationAgent2D, методы движения). Документируйте версии и используемые узлы в README проекта.

Краткая сводка

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

Важное

Если вы используете внешние звуки или ассеты, убедитесь в наличии лицензий и прав на распространение.

Заключение

Добавление разнообразных врагов — это не только код: это дизайн, художество, звук и итеративный баланс. Используйте предложенные шаблоны и чеклисты в качестве основы, но адаптируйте их под механики вашей игры. Начните с простых прототипов, затем усложняйте поведение, проверяя влияние на игровой процесс.


Факто‑блок: ключевые моменты

  • Основные узлы: KinematicBody2D, StaticBody2D, Area2D
  • Полезные практики: пул объектов для частых инстансов, FSM/BT для сложного AI
  • Тесты: поведение при столкновениях, утечки памяти, нагрузочное тестирование

Mermaid‑дерево принятия решений (управление типом врага):

flowchart TD
    A[Требуется враг?] --> B{Должен ли он двигаться?}
    B -- Нет --> C[StaticBody2D]
    B -- Да --> D{Должен ли он преследовать?}
    D -- Да --> E[KinematicBody2D + follow AI]
    D -- Нет --> F{Должен ли стрелять?}
    F -- Да --> G[KinematicBody2D + Shooting + пул]
    F -- Нет --> H[Random/Patrol]

иллюстрация узлов врагов и их взаимодействий

Короткое резюме:

  • Планируйте роль врага и его взаимодействие с игроком;
  • Делайте поведение модульным и настраиваемым;
  • Тестируйте производительность и хитбоксы на ранних стадиях разработки.
Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

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

Routinery — приложение для привычек и самоухода
Приложения

Routinery — приложение для привычек и самоухода

Как управлять шрифтами в Windows
Инструменты

Как управлять шрифтами в Windows

Opera VPN на Android — настройка и обзор
Безопасность

Opera VPN на Android — настройка и обзор

Проверка доступности сайтов на Python
Python

Проверка доступности сайтов на Python

Исправить голосовой ввод в Windows 11 — руководство
Windows

Исправить голосовой ввод в Windows 11 — руководство

Как открыть Local Users and Groups в Windows 11
Windows

Как открыть Local Users and Groups в Windows 11