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

Система здоровья и урона в Godot

6 min read Разработка игр Обновлено 20 Dec 2025
Система здоровья и урона в Godot — руководство
Система здоровья и урона в Godot — руководство

Аркадная сцена с индикаторами здоровья и очков

Введение

Система здоровья и урона (health & damage) — базовый элемент многих игр. Она позволяет игроку получать урон от препятствий или врагов, терять очки здоровья и восстанавливаться с помощью предметов или баффов. Хорошая реализация должна быть простой для тестирования, расширяемой и отделённой от UI.

В этом руководстве показаны практические подходы для 2D-проекта в Godot: от узлов сцены до взаимодействия с HUD и дополнительных игровых механик (подборы, неуязвимость, регенерация). Все примеры написаны на GDScript и ориентированы на Godot 3.x / 4.x (уточните методы API под вашу версию).

Important: примеры используют понятия “игрок”, “HUD” и “предметы”; замените имена узлов и пути в коде под вашу структуру сцены.

Архитектура: разделение ответственности

Коротко: игрок хранит состояние (здоровье, неуязвимость и т.д.) и испускает сигналы при изменении состояния. HUD подписывается на эти сигналы и обновляет полосу здоровья. Предметы и враги вызывают методы игрока (apply_damage, heal, apply_invincibility), не меняя внутреннюю логику отображения.

Преимущества такого подхода:

  • Лёгкость тестирования логики без UI.
  • Повторное использование HUD в других сценах.
  • Чистые точки интеграции для новых механик (регенирация, баффы).

Быстрая структура сцены (рекомендуемая)

  • Main (Node2D)
    • Player (KinematicBody2D / CharacterBody2D)
      • CollisionShape2D
      • Sprite
    • Enemy (Area2D / KinematicBody2D)
    • HUD (CanvasLayer)
      • TextureProgress (Полоса здоровья)
    • HealthPickup (Area2D)

Простая сцена с игровым персонажем

Базовый скрипт игрока (Player.gd)

Ниже — улучшенная версия скрипта игрока. Основные отличия: max_health, сигнал health_changed, метод apply_damage с учётом неуязвимости, и таймер для контроля урона при выходе за границы.

# Player.gd
extends KinematicBody2D

signal health_changed(new_health)
signal died()

const SPEED = 200
const EXIT_DAMAGE = 5      # урон за выход за границу (целые значения удобнее для UI)
const EXIT_DAMAGE_COOLDOWN = 1.0 # секунда между ударами за выход за границы

var velocity := Vector2.ZERO
var max_health := 100
var health := 100
var invincible := false

onready var _exit_damage_timer := Timer.new()

func _ready():
    add_child(_exit_damage_timer)
    _exit_damage_timer.wait_time = EXIT_DAMAGE_COOLDOWN
    _exit_damage_timer.one_shot = true

func _physics_process(delta):
    velocity = Vector2.ZERO
    if Input.is_action_pressed("ui_right"):
        velocity.x += SPEED
    elif Input.is_action_pressed("ui_left"):
        velocity.x -= SPEED

    if Input.is_action_pressed("ui_down"):
        velocity.y += SPEED
    elif Input.is_action_pressed("ui_up"):
        velocity.y -= SPEED

    move_and_collide(velocity * delta)
    _check_screen_bounds()

func _check_screen_bounds():
    var screen_rect = get_viewport_rect()
    var margin = 20
    var outside = position.x < -margin or position.x > screen_rect.size.x + margin or position.y < -margin or position.y > screen_rect.size.y + margin
    if outside and not _exit_damage_timer.is_stopped():
        return
    if outside and _exit_damage_timer.is_stopped():
        apply_damage(EXIT_DAMAGE)
        _exit_damage_timer.start()

func apply_damage(amount: int):
    if invincible:
        return
    health = clamp(health - int(amount), 0, max_health)
    emit_signal("health_changed", health)
    if health <= 0:
        emit_signal("died")

func heal(amount: int):
    health = clamp(health + int(amount), 0, max_health)
    emit_signal("health_changed", health)

func set_invincible(duration: float):
    if duration <= 0:
        return
    invincible = true
    var t = Timer.new()
    add_child(t)
    t.wait_time = duration
    t.one_shot = true
    t.connect("timeout", callable(self, "_end_invincible"))
    t.start()

func _end_invincible():
    invincible = false

func get_health_percent() -> float:
    return float(health) / float(max_health) * 100.0

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

HUD: обновление полосы здоровья через сигнал

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

# HUD.gd
extends CanvasLayer

onready var health_bar := $TextureProgress

func _ready():
    var player = get_parent().get_node("Player")
    if player:
        player.connect("health_changed", callable(self, "_on_health_changed"))
        player.connect("died", callable(self, "_on_player_died"))
        # Инициализация
        _on_health_changed(player.health)

func _on_health_changed(new_health):
    health_bar.value = new_health

func _on_player_died():
    # Отобразить экран «Game Over» или запустить логику перезапуска
    print("Игрок погиб")

Важно: TextureProgress можно настроить таким образом, чтобы максимальное значение соответствовало max_health. В инспекторе задайте max_value = 100 (или max_health).

Предметы лечения (Health Pickup)

Простой скрипт для предмета, который восстанавливает здоровье при подборе.

# HealthPickup.gd
extends Area2D

export var heal_amount := 25

func _on_body_entered(body):
    if body is KinematicBody2D and body.has_method("heal"):
        body.heal(heal_amount)
        queue_free()  # удалить предмет после поднятия

# Подключите сигнал body_entered в редакторе или через код

Совет: добавьте анимацию появления и звук при подборе.

Неуязвимость и визуальная индикация

Реализация метода set_invincible(duration) в Player.gd позволяет давать игроку временную неуязвимость. Для лучшей UX добавьте мельканье спрайта, изменение цветовой гаммы или частички.

Пример простого индикационного кода:

# Внутри Player.gd
func _process(delta):
    if invincible:
        $Sprite.modulate = Color(1, 1, 1, 0.6 + 0.4 * sin(OS.get_ticks_msec() / 100.0))
    else:
        $Sprite.modulate = Color(1,1,1,1)

Дополнительные механики и идеи (краткий список)

  • Регенерация: запускать таймер, который через заданный интервал прибавляет здоровье, если игрок не получает урон.
  • Разные типы урона: физический, магический, от падения — использовать структуру damage(type, amount).
  • Сопротивления/броня: добавлять уменьшение урона по формуле.
  • Критические удары/муншоты: шанс увеличить урон.

Игровой дизайн: баланс и поведение

Подсказки:

  • Выдерживайте консистентность: мелкие предметы лечения ~10–25 HP, большие ~50–100.
  • Не делайте регенерацию чрезмерно быстрой — игроки не должны лечиться без риска.
  • Тестируйте режимы игры с реальными игроками: ощущения важнее чисел.

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

  • Игрок получает урон при столкновении с врагом и при выходе за границы.
  • Полоса здоровья в HUD синхронизируется с текущим здоровьем игрока.
  • Подбор предмета лечения увеличивает здоровье, но не превышает максимум.
  • Режим неуязвимости защищает от урона на заявленное время и даёт визуальную индикацию.
  • При здоровье 0 испускается сигнал died и запускается логика «концовки игры».

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

  1. Стандартный урон: при apply_damage(20) здоровье уменьшается на 20, а HUD отражает изменение.
  2. Переполнение лечения: при heal(200) здоровье не превышает max_health.
  3. Неуязвимость: при set_invincible(2.0) любые apply_damage не меняют здоровье в течение 2 сек.
  4. Урон при выходе за границу: выйти за экран — здоровье уменьшилось на EXIT_DAMAGE и больше не уменьшается повторно в течение EXIT_DAMAGE_COOLDOWN.
  5. Смерть: здоровье дошло до 0 — получен сигнал died.

Чек-листы по ролям

Дизайнер:

  • Прописать численные значения max_health, heal_amount, скорости регенерации.
  • Подготовить спрайты/эффекты для неуязвимости и приёма урона.

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

  • Подключить сигналы между Player и HUD.
  • Обработать крайние случаи (null-ссылки, отсутствие HUD).
  • Добавить логирование для отладки (временно).

QA:

  • Протестировать на разных разрешениях экрана.
  • Провести стресс-тест: быстрые столкновения, множественные подбираемые предметы.

Мини-методология балансировки (эмпирическая)

  1. Установите базовый max_health (например 100).
  2. Определите средний урон врага за секунду (DPS) в одной сложности.
  3. Подберите heal_amount так, чтобы подбор одного предмета давал игроку конкурентное преимущество, но не делал игру слишком лёгкой.
  4. Тестируйте и корректируйте значения, опираясь на игровые сессии.

Шаблон таблицы параметров (для согласования)

ПараметрОписаниеРекомендуемое значение
max_healthМаксимум HP игрока100
EXIT_DAMAGEУрон при выходе за границы5
EXIT_DAMAGE_COOLDOWNПауза между уронами за выход1.0 с
heal_amount (малый)Малый предмет лечения25
invincibility_timeВремя неуязвимости2.0 с

Примеры отказа/когда это не работает

  • Проект с полностью абстрактной механикой (без HP) не нуждается в такой системе.
  • В играх с высокой скоростью и большим количеством врагов подход с частыми сигналами может быть узким местом; примените оптимизацию или батчинг событий.

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

Система здоровья не хранит чувствительных данных, тем не менее:

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

Галерея крайних случаев

  • Множественные подбирания предметов в один кадр — убедитесь, что heal() корректно обрабатывает клэмпинг до max_health.
  • Быстрые столкновения — используйте короткую систему задержек (invincibility frames), чтобы избежать мгновенной смерти.

Короткий словарь терминов

  • HP — здоровье персонажа.
  • DPS — урон в секунду.
  • FOV — поле зрения (не связано напрямую, но может влиять на вынос игрока за пределы).

Интерфейс Godot с полосой здоровья и узлами игрока

Резюме

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

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

Important: адаптируйте код под версию Godot (API в 4.x отличается по именам узлов и методам). Удачной разработки!

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

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

Очистка кэша на Amazon Fire TV
Руководство

Очистка кэша на Amazon Fire TV

Как настроить и использовать умную розетку
Умный дом

Как настроить и использовать умную розетку

Google Docs: режим только для просмотра
Инструкции

Google Docs: режим только для просмотра

Snarl — менеджер уведомлений для Windows
Утилиты

Snarl — менеджер уведомлений для Windows

Как использовать Steam Achievement Manager (SAM)
Игры

Как использовать Steam Achievement Manager (SAM)

Как смотреть Apple TV+ на Google TV и Android
Стриминг

Как смотреть Apple TV+ на Google TV и Android