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

Враги в Godot: создание, поведение и лучшие практики

7 min read Разработка игр Обновлено 31 Dec 2025
Враги в Godot: создание и поведение
Враги в Godot: создание и поведение

Варвар-друз сражается с врагами на простой сцене

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

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

  • Пошаговая инструкция по созданию игрока и основных типов врагов в Godot.
  • Полные скрипты на GDScript для: движения игрока, преследования, стрельбы и случайного перемещения.
  • Практические советы по визуальной коммуникации, балансировке и звуку.
  • Check-листы и критерии приёмки для команды (программисты, дизайнеры, тестирование).
  • Мини‑методология итеративной разработки врагов и варианты поведения.

Настройка 2D-проекта в Godot

Перед тем как добавлять врагов, создайте базовую структуру 2D-игры в Godot.

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

Репозиторий с кодом, использованным в статье, доступен под MIT-лицензией (ссылка в исходном проекте). Ниже — минимальный скрипт движения игрока. Он позволяет перемещаться влево/вправо/вверх/вниз с помощью стрелок или WASD.

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

    move_and_slide(motion)

Важно: используйте move_and_slide для простого движения по плоскости. Для тонкой физики и столкновений рассмотрите move_and_collide или собственные проверки столкновений.

Простая сцена с узлом Player и хитбоксом

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

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

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

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

Враг, который преследует игрока

Враги, преследующие игрока, создают ощущение преследования и напряжения. Ниже — сценa с KinematicBody2D и кодом FollowEnemy.

  1. Создайте сцену FollowEnemy.
  2. Добавьте KinematicBody2D, назовите FollowEnemy.
  3. Добавьте CollisionShape2D и Sprite.
  4. Привяжите следующий скрипт к узлу FollowEnemy:
extends KinematicBody2D

const SPEED = 100

func _physics_process(delta):
    var player = get_parent().get_node("Player")
    if player == null:
        return
    var player_position = player.global_position
    var enemy_position = global_position
    var direction = (player_position - enemy_position)
    if direction.length() == 0:
        return
    direction = direction.normalized()

    var motion = direction * SPEED
    move_and_collide(motion * delta)

Примечание: важно проверять, существует ли узел Player, чтобы избежать ошибок при динамическом удалении/создании сцен.

Узел врага, преследующий игрока, на сцене Godot

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

  • Ограничение зоны обнаружения (range): враг преследует игрока только внутри радиуса.
  • Задержка реакции: добавьте таймер перед началом движения.
  • Патруль + преследование: враг патрулирует маршрут, но переключается в режим преследования при обнаружении игрока.

Добавление вражеских пуль

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

  1. Создайте сцену Bullet.tscn.
  2. Добавьте KinematicBody2D и привяжите к нему Bullet.gd.
  3. Настройте CollisionShape2D и Sprite.

Пример скрипта для пули:

extends KinematicBody2D

const BULLET_SPEED = 300
var bullet_direction = Vector2.ZERO

func _physics_process(delta):
    var motion = bullet_direction * BULLET_SPEED
    move_and_collide(motion * delta)

func set_direction(direction: Vector2) -> void:
    if direction.length() == 0:
        bullet_direction = Vector2(1, 0)
    else:
        bullet_direction = direction.normalized()

Скрипт стреляющего врага (ShootingEnemy):

extends KinematicBody2D

const SPEED = 100
const SHOOT_DELAY = 1.5
var shoot_timer = SHOOT_DELAY

# Загрузите сцену пули
const BulletScene = preload("res://Bullet.tscn")

func _physics_process(delta):
    # Логика стрельбы
    shoot_timer -= delta
    if shoot_timer <= 0:
        shoot_timer = SHOOT_DELAY
        var player = get_parent().get_node("Player")
        if player == null:
            return
        var direction = (player.global_position - global_position)
        var bullet_instance = BulletScene.instance()
        bullet_instance.global_position = global_position
        bullet_instance.set_direction(direction)
        get_parent().add_child(bullet_instance)

Важно: пули нужно правильно удалять при выходе за границы экрана или при столкновениях (queue_free()). Также учитывайте дружелюбный огонь и фильтры слоёв столкновений.

Схема врага, стреляет пулями в сторону игрока

Враг со случайным движением

Случайное движение делает игру менее предсказуемой. Ниже — пример RandomEnemy с периодической сменой направления.

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():
    randomize()
    _choose_new_direction()

func _choose_new_direction():
    move_interval = rand_range(MOVE_INTERVAL_MIN, MOVE_INTERVAL_MAX)
    move_timer = move_interval
    var x = randf() * 2.0 - 1.0
    var y = randf() * 2.0 - 1.0
    move_direction = Vector2(x, y)
    if move_direction.length() == 0:
        move_direction = Vector2(1, 0)
    move_direction = move_direction.normalized()

func _physics_process(delta):
    move_timer -= delta
    if move_timer <= 0.0:
        _choose_new_direction()
    var motion = move_direction * MOVE_SPEED
    move_and_collide(motion * delta)

Небольшая доработка: добавьте проверку столкновений и поворот направления при упоре в стену.

Дополнительные механики: идеи и рекомендации

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

  • Боссы: большие враги с несколькими фазами и уникальной механикой.
  • Динамическое спаунение: система, подстраивающая количество и сложность врагов под прогресс игрока.
  • Адаптация к окружению: враги, которые умеют летать, плавать или лазать по стенам.
  • Слабости и сопротивления: разные типы урона, элементальные взаимодействия.
  • Вариации поведения: случайные модификаторы атак и скоростей для повторной реиграбельности.

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

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

Ясная визуальная коммуникация

Создавайте контрастные силуэты и используйте цветовую кодировку для разных типов врагов. Анимация и эффекты должны прямо указывать на состояние врага (атака, уязвимость, оглушение).

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

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

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

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

Проигрывания и итерации

Регулярно проводите плейтесты, собирайте обратную связь и итеративно улучшайте поведение врагов. Малые фазы тестирования ускоряют балансировку.

Звуковые эффекты

Звук усиливает отдачу от удара и тему боя. Используйте свободные от авторских прав эффекты, соответствующие стилю удара и реакции врага.

Мини‑методология: быстрая итерация врагов (3 шага)

  1. Прототип: создайте базовый узел врага с простым поведением (статичный/патруль/преследование).
  2. Тест: поместите врага в уровень, проведите 5–10 игровых сессий, соберите заметки.
  3. Полировка: настройте скорости, интервалы, хитбоксы, добавьте VFX/SFX.

Повторяйте цикл для каждого нового типа врага.

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

  • Враг корректно спаунится и удаляется без утечек памяти (queue_free или освобождение при удалении сцены).
  • Коллизии работают корректно: игрок получает урон только при реальном контакте.
  • Звуковые и визуальные подсказки присутствуют для всех опасных атак.
  • Враги не вызывают неожиданных падений FPS при массовых появлений.
  • Поведение врагов предсказуемо в пределах объявленных правил (патруль, преследование, стрельба).

Check-листы по ролям

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

  • Написан код с проверками на null.
  • Используются слои и маски столкновений.
  • Пули очищаются при выходе за пределы сцены.
  • Скрипты документированы краткими комментариями.

Дизайнер механик:

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

Тестировщик:

  • Проверить врага на всех платформах (если применимо).
  • Проверить поведение при массовом появлении (стресс‑тест).
  • Проверить взаимодействие с окружением (столкновения с препятствиями).

Риски и способы смягчения

  • Риск: враги вызывают падение производительности при большом количестве. Смягчение: пулл объектов для пуль и врагов, LOD-логика для поведения вне экрана.
  • Риск: неконсистентный урон из-за плохих хитбоксов. Смягчение: визуализируйте хитбоксы в режиме разработки и тестируйте с разными разрешениями.
  • Риск: игрок не понимает механику босса. Смягчение: добавьте обучение/подсказки и ясные анимации фаз.

Шаблон: таблица параметров врага (пример)

ПараметрЗначение по умолчаниюОписание
Скорость100Пикселей в секунду
HP3Количество попаданий, чтобы уничтожить
Урон1Урон игроку при контакте
Интервал стрельбы1.5 сДля стреляющих врагов
Радиус обнаружения300 пикселейДля преследующих врагов

(Примечание: значения настраиваемы для каждого врага.)

Коды-паттерны и сниппеты (cheat sheet)

  • Пул объектов: используйте массив предсозданных экземпляров и включайте/выключайте их, чтобы избежать частого вызова instance()/queue_free().
  • Маски столкновений: настраивайте слои (collision_layer) и маски (collision_mask) для отделения дружественных пуль от вражеских.
  • Таймеры: для задержек используйте Timer-узлы или собственные переменные и уменьшайте их в _process/_physics_process.

Негативные примеры: когда что-то идёт не так

  • Враг слишком силён из-за большого хитбокса — игрок чувствует, что «попадает по воздуху».
  • Пули не удаляются — со временем память увеличивается, FPS падает.
  • Враг застревает в геометрии при использовании move_and_collide без проверки обнаружения стен.

Короткая методика отладки

  1. Включите отладочный отрисовщик форм (Visible Collision Shapes) в Godot.
  2. Логируйте позиции и направления движения врага (print) в режиме разработки.
  3. Используйте ограничение скорости и clamping векторов, чтобы избегать NaN/Inf значений.

1‑строчный глоссарий

  • KinematicBody2D — узел для управления движением через код.
  • CollisionShape2D — форма столкновения (хитбокс).
  • move_and_slide / move_and_collide — методы перемещения тел с обработкой столкновений.
  • preload() — загрузка сцены или ресурса на этапе исполнения.

Заключение

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

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

Краткий план действий для следующего спринта:

  • Прототип: реализовать пул для пуль и тесты массового спавна.
  • Дизайн: прописать 3 типа врагов с параметрами и слабостями.
  • QA: провести стресс‑тест и собрать метрики падения FPS и частоты ошибок.

Дополнительные материалы и примеры кода находятся в репозитории проекта.

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

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

Как отключить режим «Сон» на iPhone
iPhone

Как отключить режим «Сон» на iPhone

Canva Brand Kit: как создать и использовать
Дизайн

Canva Brand Kit: как создать и использовать

Стоит ли бросать Evernote — причины и план перехода
Продуктивность

Стоит ли бросать Evernote — причины и план перехода

Отключение уведомлений на iPhone — полное руководство
iPhone

Отключение уведомлений на iPhone — полное руководство

Как играть в Pokémon на iPhone
iOS игры

Как играть в Pokémon на iPhone

Отключить «Уведомить в любом случае» на iPhone
iOS

Отключить «Уведомить в любом случае» на iPhone