Unreal EngineJuniorTechnical

В чём разница между Blueprints и C++ в Unreal Engine? Когда выбирать каждый из них?

Blueprints — визуальный скриптинг для быстрой итерации и работы дизайнеров, но медленнее C++ в 10–100 раз на горячих путях. C++ — для базовых классов, производительной логики и плагинов. Золотой стандарт: C++ как основа, Blueprint — для настройки и расширения.

Blueprints vs C++ в Unreal Engine

Blueprints — это визуальный скриптовый язык внутри UE Editor, построенный поверх системы Unreal Reflection. C++ — нативный код, компилируемый в машинный. Оба подхода используют один и тот же движок и могут взаимодействовать друг с другом.

Blueprints: возможности и ограничения

  • Итерация без перекомпиляции: изменения применяются через кнопку Compile в Editor — горячий путь для дизайнеров и геймдизайнеров.
  • Визуальный граф: удобен для логики «если событие — то действие», анимационных деревьев, UI-биндингов.
  • Производительность: BP-код выполняется через виртуальную машину (VM), которая в 10–100 раз медленнее нативного C++ на горячих путях (например, Tick с тысячами акторов).
  • Ограниченные возможности: нет прямого доступа к шаблонам C++, SIMD, низкоуровневым API памяти. Некоторые API доступны только через C++.
  • Нет системы контроля версий для графов: мёрджить BP-файлы (.uasset) — боль; бинарный формат плохо читается в diff.

C++: возможности и ограничения

  • Производительность: нативный код, оптимизируется компилятором. Критичные пути (физика, AI, геймплей с тысячами объектов) пишутся на C++.
  • Полный доступ к движку: Subsystem'ы, плагины, рендер-делегаты, ниткобезопасные конструкции — только C++.
  • Горячая перезагрузка: Live Coding позволяет применять часть изменений без полной перекомпиляции, но не всегда стабильно.
  • Крутая кривая входа: UCLASS, UPROPERTY, UFUNCTION макросы, UBT, Header Tool — требуют времени на освоение.

Интеграция: C++ + Blueprint

Стандартный паттерн: C++ определяет структуру и базовую логику, Blueprint расширяет и настраивает. Это золотой стандарт в студиях.

// AWeaponBase.h — базовый класс на C++
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "WeaponBase.generated.h"

UCLASS(Abstract, Blueprintable)
class MYGAME_API AWeaponBase : public AActor
{
    GENERATED_BODY()
public:
    // Вызывается из Blueprint при нажатии кнопки стрельбы
    UFUNCTION(BlueprintCallable, Category="Weapon")
    void Fire();

    // Blueprint переопределяет визуальный эффект выстрела
    UFUNCTION(BlueprintImplementableEvent, Category="Weapon")
    void OnFired();

    // Blueprint может переопределить и вызвать Super
    UFUNCTION(BlueprintNativeEvent, Category="Weapon")
    float GetDamage() const;
    virtual float GetDamage_Implementation() const;

protected:
    UPROPERTY(EditDefaultsOnly, Category="Weapon")
    float BaseDamage = 25.f;

    UPROPERTY(EditDefaultsOnly, Category="Weapon")
    float FireRate = 0.15f;

private:
    float LastFireTime = 0.f;
};

// AWeaponBase.cpp
#include "WeaponBase.h"

void AWeaponBase::Fire()
{
    const float Now = GetWorld()->GetTimeSeconds();
    if (Now - LastFireTime < FireRate) return;
    LastFireTime = Now;

    const float Damage = GetDamage(); // вызовет BP-переопределение если есть
    // ... логика применения урона ...

    OnFired(); // BP-реализация спауна партикл-эффектов
}

float AWeaponBase::GetDamage_Implementation() const
{
    return BaseDamage;
}

В Blueprint создаётся дочерний класс BP_Rifle, наследующий от AWeaponBase. Дизайнер задаёт BaseDamage, FireRate, подключает мэш, звук, партиклы — без касания C++.

Когда выбирать Blueprint

  • Прототипирование геймплея — быстрая итерация важнее производительности.
  • Уровневые события, катсцены, триггеры — логика «однажды».
  • UI (UMG) — биндинги, анимации виджетов, простая логика экранов.
  • Работа геймдизайнеров и художников без C++-компетенций.

Когда выбирать C++

  • Горячие пути: Tick с большим числом объектов, физика, AI-деревья.
  • Базовые классы (ACharacter, AGameMode, GameInstance) — их структура не должна меняться часто.
  • Плагины, Subsystem'ы, сетевые протоколы.
  • Командная работа с git — C++ читается в diff, Blueprint — нет.

Подводные камни

  • «Всё в Blueprint»: большие BP-графы становятся нечитаемыми и медленными. Тяжёлую логику переносят в C++.
  • «Всё в C++»: дизайнеры лишены возможности настраивать параметры без программиста. Используйте EditDefaultsOnly для экспонирования переменных.
  • BlueprintImplementableEvent без реализации: если Blueprint не переопределил метод, вызов просто игнорируется — это может быть неожиданным.
  • Циклические ссылки в BP: Blueprint A ссылается на Blueprint B, B ссылается на A — огромное время загрузки и трудноотловимые краши.
  • Live Coding нестабилен: добавление UPROPERTY/UFUNCTION через Live Coding часто требует полной перекомпиляции — не полагайтесь на него для структурных изменений.
  • Версионирование .uasset: BP-файлы бинарные. Конфликты мёрджа не разрешаются стандартными git-инструментами — нужны соглашения о разветвлении.
  • Нарушение инкапсуляции через Blueprint: публикация лишних переменных через UPROPERTY(BlueprintReadWrite) без необходимости ломает инкапсуляцию так же, как публичные поля в C++.

Common mistakes

  • Объяснять Blueprints и C++ только по синтаксису, без жизненного цикла и стоимости.
  • Игнорировать ошибки, null/empty состояния, порядок инициализации или режим сборки.
  • Давать пример, который работает в демо, но ломается при изменении владельца ресурса.
  • Использовать макросы или specifier-и наугад и забывать про UObject GC.

What the interviewer is testing

  • Кандидат формулирует точную модель для Blueprints и C++, а не только определение.
  • Пример компилируем, безопасен по lifetime и соответствует версии технологии.
  • Названы trade-off, ограничения и диагностируемые симптомы ошибки.
  • Понимает границу между C++ кодом, runtime/framework metadata и editor/UI слоем.

Sources

Related topics